聊天系统断网重连及客服离线识别 完成
This commit is contained in:
Binary file not shown.
@@ -1,46 +1,7 @@
|
|||||||
<!--
|
|
||||||
聊天小组件组件
|
|
||||||
|
|
||||||
=== 用户体验优化策略 v2.0 ===
|
|
||||||
|
|
||||||
遵循"静默可靠性"原则,减少90%的用户提示噪音:
|
|
||||||
|
|
||||||
✅ 已移除的不必要提示:
|
|
||||||
- 自动重连进度通知(后台静默处理)
|
|
||||||
- 图片上传进度toast(仅在失败时提示)
|
|
||||||
- 连接成功确认提示(成功是默认期望)
|
|
||||||
- 网络断开自动提示(避免打断用户)
|
|
||||||
- 订阅失败技术细节(简化为用户友好消息)
|
|
||||||
- 心跳检测正常状态日志(避免日志污染)
|
|
||||||
- WebSocket技术性错误代码(转换为友好消息)
|
|
||||||
- 连接数上限等技术术语(简化为通用连接异常)
|
|
||||||
- 系统内部状态变更通知(对用户无意义)
|
|
||||||
- 自动恢复功能的成功提示(静默恢复更专业)
|
|
||||||
|
|
||||||
✅ 保留的必要提示:
|
|
||||||
- 文件上传错误(需要用户重新操作)
|
|
||||||
- 消息发送失败(需要用户重试)
|
|
||||||
- 严重错误需要页面刷新(需要用户行动)
|
|
||||||
- 登录状态变更确认(重要状态变化)
|
|
||||||
- 需要用户手动干预的错误(如页面刷新)
|
|
||||||
|
|
||||||
✅ 优化效果:
|
|
||||||
- 大幅减少用户界面干扰
|
|
||||||
- 系统显得更稳定可靠
|
|
||||||
- 只有真正需要用户关注的信息才会显示
|
|
||||||
- 技术细节完全对用户屏蔽
|
|
||||||
- 开发调试信息保留在控制台
|
|
||||||
|
|
||||||
✅ 错误消息简化策略:
|
|
||||||
- 移除错误代码和技术术语
|
|
||||||
- 统一使用"连接异常"代替具体技术错误
|
|
||||||
- 提供明确的用户行动指导
|
|
||||||
- 避免让用户看到系统内部状态
|
|
||||||
-->
|
|
||||||
<template>
|
<template>
|
||||||
<div class="chat-widget">
|
<div class="chat-widget">
|
||||||
<!-- 添加网络状态提示 -->
|
<!-- 添加网络状态提示 -->
|
||||||
<div v-if="networkStatus === 'offline'" class="network-status">
|
<div class="network-status" v-if="networkStatus === 'offline'">
|
||||||
<i class="el-icon-warning"></i>
|
<i class="el-icon-warning"></i>
|
||||||
<span>{{ $t("chat.networkError") || "网络连接已断开" }}</span>
|
<span>{{ $t("chat.networkError") || "网络连接已断开" }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -246,10 +207,10 @@
|
|||||||
/>
|
/>
|
||||||
<!-- <span class="input-counter">{{ maxMessageLength - inputMessage.length }}</span> -->
|
<!-- <span class="input-counter">{{ maxMessageLength - inputMessage.length }}</span> -->
|
||||||
</div>
|
</div>
|
||||||
|
<!-- :disabled="connectionStatus !== 'connected' || !inputMessage.trim()" -->
|
||||||
<button
|
<button
|
||||||
class="chat-send"
|
class="chat-send"
|
||||||
@click="sendMessage"
|
@click="sendMessage"
|
||||||
:disabled="connectionStatus !== 'connected' || !inputMessage.trim()"
|
|
||||||
>
|
>
|
||||||
{{ $t("chat.send") || "发送" }}
|
{{ $t("chat.send") || "发送" }}
|
||||||
</button>
|
</button>
|
||||||
@@ -339,6 +300,7 @@ export default {
|
|||||||
lastErrorTime: 0, // 最后一次错误时间
|
lastErrorTime: 0, // 最后一次错误时间
|
||||||
lastConnectedEmail: null, // 最后连接的用户email,用于防止重复连接
|
lastConnectedEmail: null, // 最后连接的用户email,用于防止重复连接
|
||||||
userViewHistory: false, // 是否在查看历史消息
|
userViewHistory: false, // 是否在查看历史消息
|
||||||
|
customerIsOnline: true, // 保存客服在线状态
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -522,6 +484,8 @@ export default {
|
|||||||
if (userData) {
|
if (userData) {
|
||||||
this.roomId = userData.id;
|
this.roomId = userData.id;
|
||||||
this.receivingEmail = userData.userEmail;
|
this.receivingEmail = userData.userEmail;
|
||||||
|
// === 保存客服在线状态 ===
|
||||||
|
this.customerIsOnline = userData.customerIsOnline;
|
||||||
// === 使用localStorage管理未读消息数 ===
|
// === 使用localStorage管理未读消息数 ===
|
||||||
this.updateUnreadMessages(userData.clientReadNum || 0);
|
this.updateUnreadMessages(userData.clientReadNum || 0);
|
||||||
|
|
||||||
@@ -665,7 +629,7 @@ export default {
|
|||||||
if (!this.stompClient || !this.isWebSocketConnected) {
|
if (!this.stompClient || !this.isWebSocketConnected) {
|
||||||
console.error("❌ STOMP客户端未连接,无法订阅消息");
|
console.error("❌ STOMP客户端未连接,无法订阅消息");
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.connectionError = "连接状态异常,无法订阅消息";
|
this.connectionError =this.$t("chat.unableToSubscribe");//连接状态异常,无法订阅消息
|
||||||
this.isWebSocketConnected = false;
|
this.isWebSocketConnected = false;
|
||||||
this.showRefreshButton = false; // 连接状态异常通常可以重试解决
|
this.showRefreshButton = false; // 连接状态异常通常可以重试解决
|
||||||
this.$forceUpdate();
|
this.$forceUpdate();
|
||||||
@@ -675,7 +639,7 @@ export default {
|
|||||||
if (!this.stompClient.connected) {
|
if (!this.stompClient.connected) {
|
||||||
console.error("❌ STOMP客户端已断开,无法订阅消息");
|
console.error("❌ STOMP客户端已断开,无法订阅消息");
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.connectionError = "连接已断开,无法订阅消息";
|
this.connectionError = "chat.unableToSubscribe";//连接已断开,无法订阅消息
|
||||||
this.isWebSocketConnected = false;
|
this.isWebSocketConnected = false;
|
||||||
this.showRefreshButton = false; // 连接断开通常可以重试解决
|
this.showRefreshButton = false; // 连接断开通常可以重试解决
|
||||||
this.$forceUpdate();
|
this.$forceUpdate();
|
||||||
@@ -745,7 +709,7 @@ export default {
|
|||||||
|
|
||||||
// === 订阅异常立即设置错误状态 ===
|
// === 订阅异常立即设置错误状态 ===
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.connectionError = "连接异常,可能是多窗口冲突,请关闭其他窗口重试";
|
this.connectionError = this.$t("chat.conflict"); //连接异常,可能是多窗口冲突,请关闭其他窗口重试
|
||||||
this.isWebSocketConnected = false;
|
this.isWebSocketConnected = false;
|
||||||
this.isReconnecting = false;
|
this.isReconnecting = false;
|
||||||
this.showRefreshButton = false; // 多窗口冲突不需要刷新页面,重试即可
|
this.showRefreshButton = false; // 多窗口冲突不需要刷新页面,重试即可
|
||||||
@@ -757,33 +721,58 @@ export default {
|
|||||||
|
|
||||||
// 连接 WebSocket
|
// 连接 WebSocket
|
||||||
async connectWebSocket(selfEmail) {
|
async connectWebSocket(selfEmail) {
|
||||||
if (!selfEmail) selfEmail = this.userEmail;
|
// 健壮恢复userEmail
|
||||||
console.log("selfEmail",this.userEmail);
|
let email = selfEmail || this.userEmail;
|
||||||
|
// 1. 优先从 localStorage 查找
|
||||||
|
if (!email) {
|
||||||
|
try {
|
||||||
|
const emailData = localStorage.getItem("userEmail");
|
||||||
|
if (emailData) {
|
||||||
|
const emailObj = JSON.parse(emailData);
|
||||||
|
email = emailObj.email || emailObj.value || emailObj.userEmail || emailObj;
|
||||||
|
if (typeof email !== "string") email = "";
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 解析失败时忽略,继续后续逻辑
|
||||||
|
console.warn('[DEBUG] 解析localStorage userEmail失败:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2. 再从 sessionStorage 查找游客邮箱
|
||||||
|
if (!email) {
|
||||||
|
const guestEmail = sessionStorage.getItem("chatGuestEmail");
|
||||||
|
if (guestEmail && guestEmail.startsWith("guest_")) {
|
||||||
|
email = guestEmail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 3. 兜底生成游客邮箱
|
||||||
|
if (!email) {
|
||||||
|
email = `guest_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
sessionStorage.setItem("chatGuestEmail", email);
|
||||||
|
console.warn("[DEBUG] 自动生成游客邮箱:", email);
|
||||||
|
}
|
||||||
|
this.userEmail = email;
|
||||||
|
selfEmail = email;
|
||||||
|
console.log('[DEBUG] connectWebSocket called', {
|
||||||
|
isWebSocketConnected: this.isWebSocketConnected,
|
||||||
|
isReconnecting: this.isReconnecting,
|
||||||
|
lastConnectedEmail: this.lastConnectedEmail,
|
||||||
|
selfEmail,
|
||||||
|
userEmail: this.userEmail,
|
||||||
|
connectionStatus: this.connectionStatus
|
||||||
|
});
|
||||||
if (!selfEmail) {
|
if (!selfEmail) {
|
||||||
console.warn("🔴 connectWebSocket: 缺少用户邮箱参数,尝试重新获取用户身份");
|
console.warn('[DEBUG] connectWebSocket: 缺少用户邮箱参数');
|
||||||
// 返回一个rejected Promise而不是undefined,避免调用者对undefined调用.catch()
|
return Promise.reject(new Error('缺少用户邮箱参数'));
|
||||||
return Promise.reject(new Error("缺少用户邮箱参数"));
|
|
||||||
}
|
}
|
||||||
|
if (this.isWebSocketConnected && this.lastConnectedEmail === selfEmail) {
|
||||||
// === 多连接优化:后端支持最多10个连接,每个窗口独立连接 ===
|
console.log('[DEBUG] connectWebSocket: 已连接,复用');
|
||||||
console.log("🌐 后端支持多连接,当前窗口独立建立连接");
|
return Promise.resolve('already_connected');
|
||||||
|
|
||||||
// === 检查是否需要断开旧连接(仅在用户身份变化时) ===
|
|
||||||
if (this.isWebSocketConnected && this.lastConnectedEmail &&
|
|
||||||
this.lastConnectedEmail !== selfEmail) {
|
|
||||||
console.log(`🔄 用户身份变化 (${this.lastConnectedEmail} -> ${selfEmail}),断开旧连接`);
|
|
||||||
this.forceDisconnectAll();
|
|
||||||
} else if (this.isWebSocketConnected && this.lastConnectedEmail === selfEmail) {
|
|
||||||
console.log("✅ 相同用户已连接,复用现有连接");
|
|
||||||
return Promise.resolve("already_connected");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isReconnecting) {
|
if (this.isReconnecting) {
|
||||||
console.log("🔍 正在重连中,跳过重复连接");
|
console.log('[DEBUG] connectWebSocket: 正在重连中,跳过');
|
||||||
return Promise.resolve("reconnecting");
|
return Promise.resolve('reconnecting');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.connectionStatus = "connecting";
|
this.connectionStatus = "connecting";
|
||||||
this.isReconnecting = true;
|
this.isReconnecting = true;
|
||||||
this.connectionError = null;
|
this.connectionError = null;
|
||||||
@@ -808,8 +797,20 @@ export default {
|
|||||||
// 将 https 替换为 wss
|
// 将 https 替换为 wss
|
||||||
const baseUrl = process.env.VUE_APP_BASE_API.replace("https", "wss");
|
const baseUrl = process.env.VUE_APP_BASE_API.replace("https", "wss");
|
||||||
const wsUrl = `${baseUrl}chat/ws`;
|
const wsUrl = `${baseUrl}chat/ws`;
|
||||||
|
// === 彻底释放旧的stompClient和WebSocket对象 ===
|
||||||
|
if (this.stompClient) {
|
||||||
|
try {
|
||||||
|
this.stompClient.disconnect();
|
||||||
|
console.log('[DEBUG] 旧stompClient已disconnect');
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[DEBUG] stompClient.disconnect异常', e);
|
||||||
|
}
|
||||||
|
this.stompClient = null;
|
||||||
|
}
|
||||||
|
// === 新建连接前详细日志 ===
|
||||||
|
console.log('[DEBUG] 即将新建stompClient:', wsUrl);
|
||||||
this.stompClient = Stomp.client(wsUrl);
|
this.stompClient = Stomp.client(wsUrl);
|
||||||
this.stompClient.splitLargeFrames = true;
|
console.log('[DEBUG] stompClient对象已创建:', this.stompClient);
|
||||||
|
|
||||||
// === 新增:设置WebSocket连接超时 ===
|
// === 新增:设置WebSocket连接超时 ===
|
||||||
this.stompClient.webSocketFactory = () => {
|
this.stompClient.webSocketFactory = () => {
|
||||||
@@ -857,7 +858,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 其他错误可选处理
|
// 其他错误可选处理
|
||||||
this.connectionError = errorMessage || "连接异常";
|
this.connectionError = errorMessage || this.$t("chat.abnormal");//连接异常
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.isWebSocketConnected = false;
|
this.isWebSocketConnected = false;
|
||||||
this.isReconnecting = false;
|
this.isReconnecting = false;
|
||||||
@@ -893,7 +894,7 @@ export default {
|
|||||||
stompConnected: this.stompClient?.connected
|
stompConnected: this.stompClient?.connected
|
||||||
});
|
});
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.connectionError = "订阅失败,可能是多窗口冲突,请关闭其他窗口重试";
|
this.connectionError = this.$t("chat.conflict");//订阅失败,可能是多窗口冲突,请关闭其他窗口重试
|
||||||
this.isWebSocketConnected = false;
|
this.isWebSocketConnected = false;
|
||||||
this.isReconnecting = false;
|
this.isReconnecting = false;
|
||||||
this.showRefreshButton = true;
|
this.showRefreshButton = true;
|
||||||
@@ -926,11 +927,11 @@ export default {
|
|||||||
|
|
||||||
// === 简化连接错误消息,避免技术细节 ===
|
// === 简化连接错误消息,避免技术细节 ===
|
||||||
if (error.headers.message.includes("503")) {
|
if (error.headers.message.includes("503")) {
|
||||||
this.connectionError = "服务器暂时不可用,请稍后重试";
|
this.connectionError = this.$t("chat.server500");// "服务器暂时不可用,请稍后重试";
|
||||||
} else if (error.headers.message.includes("handshake")) {
|
} else if (error.headers.message.includes("handshake")) {
|
||||||
this.connectionError = "网络连接异常,正在重试";
|
this.connectionError =this.$t("chat.networkAnomaly");//网络连接异常,正在重试
|
||||||
} else {
|
} else {
|
||||||
this.connectionError = "连接异常,正在重试";
|
this.connectionError = this.$t(`chat.abnormal`);//连接异常,正在重试
|
||||||
}
|
}
|
||||||
this.isReconnecting = false;
|
this.isReconnecting = false;
|
||||||
this.handleDisconnect();
|
this.handleDisconnect();
|
||||||
@@ -944,7 +945,7 @@ export default {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("初始化 WebSocket 失败:", error);
|
console.error("初始化 WebSocket 失败:", error);
|
||||||
clearTimeout(connectionTimeout);
|
clearTimeout(connectionTimeout);
|
||||||
this.connectionError = "连接初始化失败,正在重试";
|
this.connectionError = this.$t("chat.initializationFailed");//初始化失败,请刷新页面重试
|
||||||
this.isReconnecting = false;
|
this.isReconnecting = false;
|
||||||
this.handleDisconnect();
|
this.handleDisconnect();
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
@@ -952,6 +953,12 @@ export default {
|
|||||||
},
|
},
|
||||||
// 添加新重连最多重连5次
|
// 添加新重连最多重连5次
|
||||||
handleDisconnect() {
|
handleDisconnect() {
|
||||||
|
console.log('[DEBUG] handleDisconnect', {
|
||||||
|
isWebSocketConnected: this.isWebSocketConnected,
|
||||||
|
isReconnecting: this.isReconnecting,
|
||||||
|
reconnectAttempts: this.reconnectAttempts,
|
||||||
|
connectionStatus: this.connectionStatus
|
||||||
|
});
|
||||||
if (this.isReconnecting) return;
|
if (this.isReconnecting) return;
|
||||||
|
|
||||||
console.log("🔌 处理连接断开...");
|
console.log("🔌 处理连接断开...");
|
||||||
@@ -1004,26 +1011,13 @@ export default {
|
|||||||
// 只记录日志,不显示toast提示
|
// 只记录日志,不显示toast提示
|
||||||
|
|
||||||
this.reconnectTimer = setTimeout(() => {
|
this.reconnectTimer = setTimeout(() => {
|
||||||
|
this.isReconnecting = false; // 兜底重置,确保重连能进入
|
||||||
if (!this.isWebSocketConnected) {
|
if (!this.isWebSocketConnected) {
|
||||||
// === 修复:传递用户邮箱参数,并处理方法可能返回undefined的情况 ===
|
|
||||||
const connectionPromise = this.connectWebSocket(this.userEmail);
|
const connectionPromise = this.connectWebSocket(this.userEmail);
|
||||||
if (connectionPromise && typeof connectionPromise.catch === 'function') {
|
if (connectionPromise && typeof connectionPromise.catch === 'function') {
|
||||||
connectionPromise.catch((error) => {
|
connectionPromise.catch((error) => {
|
||||||
console.error("🔴 自动重连失败:", error);
|
console.error('[DEBUG] 自动重连失败:', error);
|
||||||
|
|
||||||
// === 如果聊天窗口打开,确保显示错误状态 ===
|
|
||||||
if (this.isChatOpen) {
|
|
||||||
this.connectionStatus = "error";
|
|
||||||
}
|
|
||||||
this.showRefreshButton = true;
|
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
console.warn("🔴 connectWebSocket返回值无效,可能缺少userEmail");
|
|
||||||
// 如果connectWebSocket返回undefined,说明参数有问题,显示错误状态
|
|
||||||
if (this.isChatOpen) {
|
|
||||||
this.connectionStatus = "error";
|
|
||||||
}
|
|
||||||
this.showRefreshButton = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, this.reconnectInterval);
|
}, this.reconnectInterval);
|
||||||
@@ -1040,15 +1034,25 @@ export default {
|
|||||||
// 处理网络状态变化
|
// 处理网络状态变化
|
||||||
handleNetworkChange() {
|
handleNetworkChange() {
|
||||||
this.networkStatus = navigator.onLine ? "online" : "offline";
|
this.networkStatus = navigator.onLine ? "online" : "offline";
|
||||||
|
console.log('[DEBUG] handleNetworkChange', {
|
||||||
|
online: navigator.onLine,
|
||||||
|
isWebSocketConnected: this.isWebSocketConnected,
|
||||||
|
isReconnecting: this.isReconnecting,
|
||||||
|
connectionStatus: this.connectionStatus
|
||||||
|
});
|
||||||
if (navigator.onLine) {
|
if (navigator.onLine) {
|
||||||
// 网络恢复时,尝试重连
|
// === 强制重置状态,兜底 ===
|
||||||
if (!this.isWebSocketConnected) {
|
location.reload(); // 重新加载当前页面
|
||||||
this.handleDisconnect();
|
this.isChatOpen = false;
|
||||||
}
|
this.isMinimized = false;
|
||||||
} else {
|
this.isLoadingHistory = false;
|
||||||
// === 移除网络断开提示:网络状态在界面上已有显示 ===
|
this.isLoading = false;
|
||||||
console.log("🌐 网络已断开,显示网络状态提示");
|
this.isWebSocketConnected = false;
|
||||||
|
this.isReconnecting = false;
|
||||||
|
// if (!this.isWebSocketConnected) {
|
||||||
|
// console.log('[DEBUG] 网络恢复,触发 handleDisconnect');
|
||||||
|
// this.handleDisconnect();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 开始活动检测
|
// 开始活动检测
|
||||||
@@ -1101,9 +1105,36 @@ export default {
|
|||||||
},
|
},
|
||||||
// 发送消息
|
// 发送消息
|
||||||
sendMessage() {
|
sendMessage() {
|
||||||
if (!this.inputMessage.trim()) return;
|
// 网络断开时阻止发送消息并提示
|
||||||
|
if (this.networkStatus !== 'online') {
|
||||||
|
this.$message({
|
||||||
|
message: this.$t("chat.networkError") || "网络连接已断开,无法发送消息",
|
||||||
|
type: "error",
|
||||||
|
showClose: true
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// === 游客且客服离线时提示 ===
|
||||||
|
if (this.userType === 0 && this.customerIsOnline === false) {
|
||||||
|
this.$message({
|
||||||
|
message:this.$t("chat.customerServiceOffline") || "客服离线,请登录账号发送留言消息",
|
||||||
|
type: "warning",
|
||||||
|
showClose: true
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.inputMessage.trim()){
|
||||||
|
|
||||||
|
|
||||||
|
this.$message({
|
||||||
|
message: this.$t("chat.sendMessageEmpty") || "发送消息不能为空",
|
||||||
|
type: "warning",
|
||||||
|
showClose: true
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.inputMessage.length > this.maxMessageLength) {
|
if (this.inputMessage.length > this.maxMessageLength) {
|
||||||
this.$message.warning(`消息不能超过${this.maxMessageLength}个字符`);
|
this.$message.warning(this.$t("chat.contentMax") || "超出发送内容大小限制,请删除部分内容(300字以内)");//超出发送内容大小限制,请删除部分内容 300个字符
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1157,7 +1188,7 @@ export default {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("发送消息失败:", error);
|
console.error("发送消息失败:", error);
|
||||||
// === 优化发送失败提示:只在明确需要用户重试时提示 ===
|
// === 优化发送失败提示:只在明确需要用户重试时提示 ===
|
||||||
this.$message.error("发送失败,请重试");
|
this.$message.error(this.$t("chat.failInSend") || "发送失败,请重试");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1355,7 +1386,7 @@ export default {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("加载历史消息失败:", error);
|
console.error("加载历史消息失败:", error);
|
||||||
// === 简化历史消息加载失败提示 ===
|
// === 简化历史消息加载失败提示 ===
|
||||||
this.$message.error("加载历史消息失败");
|
this.$message.error(this.$t("chat.loadHistoryFailed") || "加载历史消息失败");
|
||||||
this.messages = [
|
this.messages = [
|
||||||
{
|
{
|
||||||
type: "system",
|
type: "system",
|
||||||
@@ -1446,7 +1477,7 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error("加载历史消息失败,请重试");
|
this.$message.error(this.$t("chat.loadHistoryFailed") || "加载历史消息失败,请重试");
|
||||||
} finally {
|
} finally {
|
||||||
this.isLoadingHistory = false;
|
this.isLoadingHistory = false;
|
||||||
}
|
}
|
||||||
@@ -1652,18 +1683,25 @@ export default {
|
|||||||
// 添加消息到聊天列表
|
// 添加消息到聊天列表
|
||||||
this.addMessageToChat(messageData, isSentByMe);
|
this.addMessageToChat(messageData, isSentByMe);
|
||||||
|
|
||||||
// 如果是对方发送的消息且聊天窗口未打开,增加未读消息数
|
// === 新增未读数逻辑 ===
|
||||||
if (!isSentByMe && !this.isChatOpen) {
|
if (!isSentByMe) {
|
||||||
// 使用服务器返回的未读数,如果没有则增加1
|
// 聊天框打开且在底部,自动已读
|
||||||
if (messageData.clientReadNum !== undefined) {
|
if (this.isChatOpen && this.isAtBottom()) {
|
||||||
this.updateUnreadMessages(messageData.clientReadNum);
|
this.updateUnreadMessages(0);
|
||||||
|
// 可选:自动标记已读
|
||||||
|
// this.markMessagesAsRead();
|
||||||
} else {
|
} else {
|
||||||
this.updateUnreadMessages(this.unreadMessages + 1);
|
// 聊天框未打开或不在底部,显示未读数
|
||||||
|
if (data.clientReadNum !== undefined) {
|
||||||
|
this.updateUnreadMessages(data.clientReadNum);
|
||||||
|
} else {
|
||||||
|
this.updateUnreadMessages(this.unreadMessages + 1);
|
||||||
|
}
|
||||||
|
// 显示消息通知
|
||||||
|
const messageObj = this.createMessageObject(data);
|
||||||
|
this.showNotification(messageObj);
|
||||||
}
|
}
|
||||||
// 显示消息通知
|
}
|
||||||
const messageObj = this.createMessageObject(messageData);
|
|
||||||
this.showNotification(messageObj);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1805,7 +1843,7 @@ export default {
|
|||||||
},
|
},
|
||||||
// 创建通知
|
// 创建通知
|
||||||
createNotification(message) {
|
createNotification(message) {
|
||||||
const notification = new Notification("新消息", {
|
const notification = new Notification(this.$t("chat.newMessage") || "新消息", {
|
||||||
body: message.isImage
|
body: message.isImage
|
||||||
? `[ ${this.$t("chat.pictureMessage")}]` || "[图片消息]"
|
? `[ ${this.$t("chat.pictureMessage")}]` || "[图片消息]"
|
||||||
: message.text,
|
: message.text,
|
||||||
@@ -1922,7 +1960,7 @@ export default {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("初始化聊天失败:", error);
|
console.error("初始化聊天失败:", error);
|
||||||
// === 简化初始化失败提示 ===
|
// === 简化初始化失败提示 ===
|
||||||
this.$message.error("连接失败,请重试");
|
// this.$message.error("连接失败,请重试");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// === 新增:关闭聊天时清除连接验证 ===
|
// === 新增:关闭聊天时清除连接验证 ===
|
||||||
@@ -2290,7 +2328,7 @@ export default {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("发送图片消息失败:", error);
|
console.error("发送图片消息失败:", error);
|
||||||
// === 简化图片发送失败提示 ===
|
// === 简化图片发送失败提示 ===
|
||||||
this.$message.error("图片发送失败,请重试");
|
// this.$message.error("图片发送失败,请重试");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -2375,10 +2413,10 @@ export default {
|
|||||||
error.message.includes("503") ||
|
error.message.includes("503") ||
|
||||||
error.message.includes("网络")
|
error.message.includes("网络")
|
||||||
)) {
|
)) {
|
||||||
this.connectionError = "网络连接异常,请稍后重试";
|
this.connectionError = this.$t("chat.networkAnomaly") || "网络连接异常,请稍后重试";
|
||||||
this.showRefreshButton = false; // 网络问题不显示刷新按钮
|
this.showRefreshButton = false; // 网络问题不显示刷新按钮
|
||||||
} else {
|
} else {
|
||||||
this.connectionError = "连接异常,请重试";
|
this.connectionError =this.$t("chat.abnormal") || "连接异常,请重试";
|
||||||
this.showRefreshButton = error.message && error.message.includes("1020"); // 只有1020错误才显示刷新按钮
|
this.showRefreshButton = error.message && error.message.includes("1020"); // 只有1020错误才显示刷新按钮
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2566,7 +2604,7 @@ export default {
|
|||||||
|
|
||||||
// === 立即设置错误状态 ===
|
// === 立即设置错误状态 ===
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.connectionError = "连接数已达上限(超过10个窗口),请关闭一些窗口后重试";
|
this.connectionError = this.$t("chat.connectionLimitError") || "连接数已达上限(超过10个窗口),请关闭一些窗口后重试";
|
||||||
this.isWebSocketConnected = false;
|
this.isWebSocketConnected = false;
|
||||||
this.isReconnecting = false;
|
this.isReconnecting = false;
|
||||||
this.showRefreshButton = false; // 不显示刷新按钮,用户只需关闭多余窗口
|
this.showRefreshButton = false; // 不显示刷新按钮,用户只需关闭多余窗口
|
||||||
@@ -2673,7 +2711,7 @@ export default {
|
|||||||
|
|
||||||
case "1021": // MAX_LIMIT_CONNECT
|
case "1021": // MAX_LIMIT_CONNECT
|
||||||
console.log("🚫 处理1021错误:服务器连接数上限");
|
console.log("🚫 处理1021错误:服务器连接数上限");
|
||||||
this.connectionError = "服务器繁忙,请稍后刷新重试";
|
this.connectionError = this.$t("chat.serverBusy") || "服务器繁忙,请稍后刷新重试";
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.isReconnecting = false;
|
this.isReconnecting = false;
|
||||||
this.showRefreshButton = true;
|
this.showRefreshButton = true;
|
||||||
@@ -2682,7 +2720,7 @@ export default {
|
|||||||
|
|
||||||
case "1022": // SET_PRINCIPAL_FAIL
|
case "1022": // SET_PRINCIPAL_FAIL
|
||||||
console.log("🚫 处理1022错误:身份设置失败");
|
console.log("🚫 处理1022错误:身份设置失败");
|
||||||
this.connectionError = "身份验证失败,请刷新页面重试";
|
this.connectionError = this.$t("chat.identityError") || "身份验证失败,请刷新页面重试";
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.isReconnecting = false;
|
this.isReconnecting = false;
|
||||||
this.showRefreshButton = true;
|
this.showRefreshButton = true;
|
||||||
@@ -2691,7 +2729,7 @@ export default {
|
|||||||
|
|
||||||
case "1023": // GET_PRINCIPAL_FAIL
|
case "1023": // GET_PRINCIPAL_FAIL
|
||||||
console.log("🚫 处理1023错误:用户信息获取失败");
|
console.log("🚫 处理1023错误:用户信息获取失败");
|
||||||
this.connectionError = "用户信息获取失败,请刷新页面重试";
|
this.connectionError = this.$t("chat.emailError") || "用户信息获取失败,请刷新页面重试";
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.isReconnecting = false;
|
this.isReconnecting = false;
|
||||||
this.showRefreshButton = true;
|
this.showRefreshButton = true;
|
||||||
@@ -2883,7 +2921,7 @@ export default {
|
|||||||
// 重置连接状态
|
// 重置连接状态
|
||||||
this.isWebSocketConnected = false;
|
this.isWebSocketConnected = false;
|
||||||
this.connectionStatus = "connecting"; // 改为connecting而不是error
|
this.connectionStatus = "connecting"; // 改为connecting而不是error
|
||||||
this.connectionError = "正在重新连接...";
|
this.connectionError = this.$t("chat.reconnecting") || "正在重新连接...";
|
||||||
|
|
||||||
// 2秒后重新连接
|
// 2秒后重新连接
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -2954,7 +2992,7 @@ export default {
|
|||||||
this.forceDisconnectAll().then(() => {
|
this.forceDisconnectAll().then(() => {
|
||||||
// 设置connecting状态而不是error状态
|
// 设置connecting状态而不是error状态
|
||||||
this.connectionStatus = "connecting";
|
this.connectionStatus = "connecting";
|
||||||
this.connectionError = "连接超时,正在重试...";
|
this.connectionError = this.$t("chat.connectionTimedOut") || "连接超时,稍后重试...";
|
||||||
|
|
||||||
// 2秒后重新连接
|
// 2秒后重新连接
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -2969,12 +3007,12 @@ export default {
|
|||||||
this.isChatOpen = true;
|
this.isChatOpen = true;
|
||||||
this.isMinimized = false;
|
this.isMinimized = false;
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.connectionError = "重连失败,请稍后重试";
|
this.connectionError = this.$t("chat.reconnectFailed") || "重连失败,请稍后重试";
|
||||||
|
|
||||||
// 如果已达最大重连次数,显示刷新按钮
|
// 如果已达最大重连次数,显示刷新按钮
|
||||||
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
||||||
this.showRefreshButton = true;
|
this.showRefreshButton = true;
|
||||||
this.connectionError = "连接失败,请刷新页面重试";
|
this.connectionError = this.$t("chat.connectionFailed") || "连接失败,请刷新页面重试";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 2000);
|
}, 2000);
|
||||||
@@ -2986,12 +3024,12 @@ export default {
|
|||||||
this.isChatOpen = true;
|
this.isChatOpen = true;
|
||||||
this.isMinimized = false;
|
this.isMinimized = false;
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.connectionError = "连接处理失败,请稍后重试";
|
this.connectionError = this.$t("chat.connectionFailed") ||"连接处理失败,请稍后重试";
|
||||||
|
|
||||||
// 如果已达最大重连次数,显示刷新按钮
|
// 如果已达最大重连次数,显示刷新按钮
|
||||||
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
||||||
this.showRefreshButton = true;
|
this.showRefreshButton = true;
|
||||||
this.connectionError = "连接失败,请刷新页面重试";
|
this.connectionError = this.$t("chat.connectionFailed") || "连接失败,请刷新页面重试";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -3048,19 +3086,19 @@ export default {
|
|||||||
|
|
||||||
// === 增强握手错误处理,针对不同错误码提供准确的错误信息 ===
|
// === 增强握手错误处理,针对不同错误码提供准确的错误信息 ===
|
||||||
if (error.message.includes("unexpected response code: 200")) {
|
if (error.message.includes("unexpected response code: 200")) {
|
||||||
this.connectionError = "服务配置异常,请稍后重试";
|
this.connectionError = this.$t("chat.serviceConfigurationError") || "服务配置异常,请稍后重试";
|
||||||
console.log("🔴 WebSocket握手失败:服务器返回200而非101升级响应");
|
console.log("🔴 WebSocket握手失败:服务器返回200而非101升级响应");
|
||||||
} else if (error.message.includes("unexpected response code: 404")) {
|
} else if (error.message.includes("unexpected response code: 404")) {
|
||||||
this.connectionError = "服务地址不可用,请稍后重试";
|
this.connectionError = this.$t("chat.serviceAddressUnavailable") || "服务地址不可用,请稍后重试";
|
||||||
console.log("🔴 WebSocket握手失败:服务地址404");
|
console.log("🔴 WebSocket握手失败:服务地址404");
|
||||||
} else if (error.message.includes("unexpected response code: 500")) {
|
} else if (error.message.includes("unexpected response code: 500")) {
|
||||||
this.connectionError = "服务器暂时不可用,请稍后重试";
|
this.connectionError = this.$t("chat.server500") || "服务器暂时不可用,请稍后重试";
|
||||||
console.log("🔴 WebSocket握手失败:服务器500错误");
|
console.log("🔴 WebSocket握手失败:服务器500错误");
|
||||||
} else if (error.message.includes("connection refused")) {
|
} else if (error.message.includes("connection refused")) {
|
||||||
this.connectionError = "无法连接到服务器,请稍后重试";
|
this.connectionError = this.$t("chat.connectionFailedService") || "无法连接到服务器,请稍后重试";
|
||||||
console.log("🔴 WebSocket握手失败:连接被拒绝");
|
console.log("🔴 WebSocket握手失败:连接被拒绝");
|
||||||
} else {
|
} else {
|
||||||
this.connectionError = "连接失败,请稍后重试";
|
this.connectionError = this.$t("chat.connectionFailed") || "连接失败,请稍后重试";
|
||||||
console.log("🔴 WebSocket握手失败:", error.message);
|
console.log("🔴 WebSocket握手失败:", error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3073,7 +3111,7 @@ export default {
|
|||||||
console.log("❌ 握手错误重连次数已达上限,停止重连");
|
console.log("❌ 握手错误重连次数已达上限,停止重连");
|
||||||
this.isHandlingError = false;
|
this.isHandlingError = false;
|
||||||
this.showRefreshButton = true;
|
this.showRefreshButton = true;
|
||||||
this.connectionError = "连接失败,请刷新页面重试";
|
this.connectionError = this.$t("chat.connectionFailed") || "连接失败,请刷新页面重试";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3089,7 +3127,7 @@ export default {
|
|||||||
console.error("❌ 握手错误重连失败:", retryError);
|
console.error("❌ 握手错误重连失败:", retryError);
|
||||||
this.isHandlingError = false;
|
this.isHandlingError = false;
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.connectionError = "重连失败,请稍后重试";
|
this.connectionError = this.$t("chat.reconnectFailed") || "重连失败,请稍后重试";
|
||||||
});
|
});
|
||||||
}, 3000);
|
}, 3000);
|
||||||
},
|
},
|
||||||
@@ -3110,7 +3148,7 @@ export default {
|
|||||||
// === 关键修复:立即显示错误状态和重试按钮 ===
|
// === 关键修复:立即显示错误状态和重试按钮 ===
|
||||||
this.isWebSocketConnected = false;
|
this.isWebSocketConnected = false;
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.connectionError = "连接客服系统失败,请检查网络或稍后重试";
|
this.connectionError = this.$t("chat.connectionFailedCustomer") || "连接客服系统失败,请检查网络或稍后重试";
|
||||||
this.showRefreshButton = false;
|
this.showRefreshButton = false;
|
||||||
// 1秒后可自动重连(不影响UI)
|
// 1秒后可自动重连(不影响UI)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -3129,7 +3167,7 @@ export default {
|
|||||||
this.isWebSocketConnected = false;
|
this.isWebSocketConnected = false;
|
||||||
// === 关键修复:立即显示错误状态和重试按钮 ===
|
// === 关键修复:立即显示错误状态和重试按钮 ===
|
||||||
this.connectionStatus = "error";
|
this.connectionStatus = "error";
|
||||||
this.connectionError = "连接客服系统失败,请检查网络或稍后重试";
|
this.connectionError = this.$t("chat.connectionFailedCustomer") || "连接客服系统失败,请检查网络或稍后重试";
|
||||||
this.showRefreshButton = false;
|
this.showRefreshButton = false;
|
||||||
// 延迟重连
|
// 延迟重连
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -3210,7 +3248,7 @@ export default {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.error("登录处理最终失败,已达到最大重试次数");
|
console.error("登录处理最终失败,已达到最大重试次数");
|
||||||
this.$message.error("聊天功能初始化失败,请刷新页面");
|
// this.$message.error("聊天功能初始化失败,请刷新页面");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3825,7 +3863,7 @@ export default {
|
|||||||
|
|
||||||
.network-status {
|
.network-status {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 20px;
|
top: 80px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|||||||
@@ -91,7 +91,23 @@ export const ChatWidget_zh = {
|
|||||||
emailError:"用户信息获取失败,请刷新页面重试",
|
emailError:"用户信息获取失败,请刷新页面重试",
|
||||||
refreshPage:"刷新页面",
|
refreshPage:"刷新页面",
|
||||||
reconnectSuccess:"重新连接成功",
|
reconnectSuccess:"重新连接成功",
|
||||||
},
|
sendMessageEmpty:"发送消息不能为空",
|
||||||
|
unableToSubscribe:"连接状态异常,刷新页面重试",
|
||||||
|
conflict:"连接异常,可能是多窗口冲突,请关闭其他窗口重试",
|
||||||
|
abnormal:"连接异常",
|
||||||
|
networkAnomaly:"网络连接异常",
|
||||||
|
customerServiceOffline:"客服离线,请登录账号发送留言消息",
|
||||||
|
contentMax:"超出发送内容大小限制,请删除部分内容(300字以内)",
|
||||||
|
failInSend:"发送失败,请重试",
|
||||||
|
connectionLimitError:"连接数已达上限,请关闭一些窗口后刷新重试",
|
||||||
|
serverBusy:"服务器繁忙,请稍后刷新重试",
|
||||||
|
connectionTimedOut:"连接超时,稍后重试...",
|
||||||
|
reconnectFailed:"重连失败,请稍后重试",
|
||||||
|
serviceConfigurationError:"服务配置异常,请稍后重试",
|
||||||
|
serviceAddressUnavailable:"服务地址不可用,请稍后重试",
|
||||||
|
connectionFailedService:"无法连接到服务器,请稍后重试",
|
||||||
|
connectionFailedCustomer:"连接客服系统失败,请检查网络或稍后重试",
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -157,7 +173,7 @@ export const ChatWidget_en = {
|
|||||||
None: "No messages",
|
None: "No messages",
|
||||||
sendPicture: "Send image",
|
sendPicture: "Send image",
|
||||||
inputMessage: "Type message, Enter to send, Ctrl+Enter for new line",
|
inputMessage: "Type message, Enter to send, Ctrl+Enter for new line",
|
||||||
bottom: "Back to bottom",
|
bottom: "to bottom",
|
||||||
Preview: "Preview image",
|
Preview: "Preview image",
|
||||||
chatRoom: "Chat room",
|
chatRoom: "Chat room",
|
||||||
CLOSED: "Closed",
|
CLOSED: "Closed",
|
||||||
@@ -190,7 +206,30 @@ export const ChatWidget_en = {
|
|||||||
emailError:"Failed to get user information, please refresh page",
|
emailError:"Failed to get user information, please refresh page",
|
||||||
refreshPage:"Refresh page",
|
refreshPage:"Refresh page",
|
||||||
reconnectSuccess:"Reconnect successfully",
|
reconnectSuccess:"Reconnect successfully",
|
||||||
|
sendMessageEmpty:"Message cannot be empty",
|
||||||
|
unableToSubscribe:"Connection status abnormal, please refresh the page",
|
||||||
}
|
conflict:"Connection exception, possibly due to multiple window conflicts, please close other windows and try again",
|
||||||
|
abnormal:"Connection exception",
|
||||||
|
networkAnomaly:"Network connection exception",
|
||||||
|
customerServiceOffline:"Customer service offline, please login to send message",
|
||||||
|
contentMax:"Content exceeds the size limit, please delete some content(300 characters or less)",
|
||||||
|
failInSend:"Failed to send, please try again",
|
||||||
|
connectionLimitError:"Connection limit reached, please close some windows and refresh to try again",
|
||||||
|
serverBusy:"Server busy, please refresh later",
|
||||||
|
connectionTimedOut:"Connection timed out, please try again later",
|
||||||
|
reconnectFailed:"Reconnect failed, please try again later",
|
||||||
|
serviceConfigurationError:"Service configuration exception, please try again later",
|
||||||
|
serviceAddressUnavailable:"Service address unavailable, please try again later",
|
||||||
|
connectionFailedService:"Failed to connect to the server, please try again later",
|
||||||
|
connectionFailedCustomer:"Failed to connect to the customer service system, please check the network or try again later",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1407,13 +1407,13 @@ export default {
|
|||||||
// 其他CSS样式可以根据需要添加
|
// 其他CSS样式可以根据需要添加
|
||||||
},
|
},
|
||||||
handelProfitCalculation() {
|
handelProfitCalculation() {
|
||||||
|
|
||||||
for (const key in this.CalculatorData) {
|
for (const key in this.CalculatorData) {
|
||||||
if (!this.CalculatorData[key]) {
|
if (this.CalculatorData[key]!==0 && !this.CalculatorData[key]) {
|
||||||
// this.$message({
|
this.$message({
|
||||||
// message: this.$t(`home.acquisitionFailed`),
|
message: this.$t(`home.acquisitionFailed`),
|
||||||
// type: "error",
|
type: "error",
|
||||||
// });
|
});
|
||||||
this.profit = 0
|
this.profit = 0
|
||||||
// var myDiv = document.getElementById('myDiv');
|
// var myDiv = document.getElementById('myDiv');
|
||||||
// this.disableElement(myDiv);
|
// this.disableElement(myDiv);
|
||||||
|
|||||||
@@ -680,6 +680,7 @@
|
|||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
|
v-show="item.value !== 'enx'"
|
||||||
>
|
>
|
||||||
<div style="display: flex; align-items: center">
|
<div style="display: flex; align-items: center">
|
||||||
<img :src="item.imgUrl" style="float: left; width: 20px" />
|
<img :src="item.imgUrl" style="float: left; width: 20px" />
|
||||||
|
|||||||
Binary file not shown.
1
mining-pool/test/css/app-189e7968.908e0479.css
Normal file
1
mining-pool/test/css/app-189e7968.908e0479.css
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/css/app-189e7968.908e0479.css.gz
Normal file
BIN
mining-pool/test/css/app-189e7968.908e0479.css.gz
Normal file
Binary file not shown.
1
mining-pool/test/css/app-72600b29.37eab263.css
Normal file
1
mining-pool/test/css/app-72600b29.37eab263.css
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/css/app-72600b29.37eab263.css.gz
Normal file
BIN
mining-pool/test/css/app-72600b29.37eab263.css.gz
Normal file
Binary file not shown.
1
mining-pool/test/css/app-8e0489d9.c5f430f0.css
Normal file
1
mining-pool/test/css/app-8e0489d9.c5f430f0.css
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/css/app-8e0489d9.c5f430f0.css.gz
Normal file
BIN
mining-pool/test/css/app-8e0489d9.c5f430f0.css.gz
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><meta name=google-site-verification content=pKAZogQ0NQ6L4j9-V58WJMjm7zYCFwkJXSJzWu9UDM8><meta name=robots content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"><meta name=googlebot content="index, follow"><meta name=googlebot-news content="index, follow"><meta name=bingbot content="index, follow"><link rel=alternate hreflang=zh href=https://m2pool.com/zh><link rel=alternate hreflang=en href=https://m2pool.com/en><link rel=alternate hreflang=x-default href=https://m2pool.com/en><meta property=og:title content="M2pool - Stable leading high-yield mining pool"><meta property=og:description content="M2Pool provides professional mining services, supporting multiple cryptocurrency mining"><meta property=og:url content=https://m2pool.com/en><meta property=og:site_name content=M2Pool><meta property=og:type content=website><meta property=og:image content=https://m2pool.com/logo.png><link rel=icon href=/favicon.ico><link rel=stylesheet href=//at.alicdn.com/t/c/font_4582735_7i8wfzc0art.css><title>M2pool - Stable leading high-yield mining pool</title><meta name=keywords content="M2Pool, cryptocurrency mining pool,Entropyx(enx),entropyx, bitcoin mining, DGB mining, mining pool service, 加密货币矿池, 比特币挖矿, DGB挖矿"><meta name=description content="M2Pool provides professional mining services, supporting multiple cryptocurrency mining, including nexa, grs, mona, dgb, rxd, enx"><meta name=format-detection content="telephone=no"><meta name=apple-mobile-web-app-capable content=yes><script defer src=/js/chunk-vendors-945ce2fe.648a91a9.js></script><script defer src=/js/chunk-vendors-aacc2dbb.d317c558.js></script><script defer src=/js/chunk-vendors-bc050c32.3f2f14d2.js></script><script defer src=/js/chunk-vendors-3003db77.d0b93d36.js></script><script defer src=/js/chunk-vendors-9d134daf.bb668c99.js></script><script defer src=/js/chunk-vendors-439af1fa.48a48f35.js></script><script defer src=/js/chunk-vendors-5c533fba.b9c00e08.js></script><script defer src=/js/chunk-vendors-96cecd74.a7d9b845.js></script><script defer src=/js/chunk-vendors-c2f7d60e.3710fdc2.js></script><script defer src=/js/chunk-vendors-89d5c698.2190b4ca.js></script><script defer src=/js/chunk-vendors-377fed06.159de137.js></script><script defer src=/js/chunk-vendors-5a805870.4cfc0ae8.js></script><script defer src=/js/chunk-vendors-cf2e0a28.c6e99da0.js></script><script defer src=/js/app-42f9d7e6.9eb6b4eb.js></script><script defer src=/js/app-d363ae0c.ec582e15.js></script><script defer src=/js/app-5c551db8.aa772a92.js></script><script defer src=/js/app-01dc9ae1.e746f05c.js></script><script defer src=/js/app-8e0489d9.cbdab613.js></script><script defer src=/js/app-72600b29.a3b71b37.js></script><script defer src=/js/app-f035d474.92e1d288.js></script><script defer src=/js/app-113c6c50.56b97e4e.js></script><link href=/css/chunk-vendors-5c533fba.6f97509c.css rel=stylesheet><link href=/css/app-189e7968.0fe23a85.css rel=stylesheet><link href=/css/app-01dc9ae1.04da7d85.css rel=stylesheet><link href=/css/app-8e0489d9.2416bb84.css rel=stylesheet><link href=/css/app-72600b29.0c194743.css rel=stylesheet><link href=/css/app-f035d474.0348646a.css rel=stylesheet><link href=/css/app-113c6c50.dfa1d227.css rel=stylesheet></head><body><div id=app></div></body></html>
|
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><meta name=google-site-verification content=pKAZogQ0NQ6L4j9-V58WJMjm7zYCFwkJXSJzWu9UDM8><meta name=robots content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"><meta name=googlebot content="index, follow"><meta name=googlebot-news content="index, follow"><meta name=bingbot content="index, follow"><link rel=alternate hreflang=zh href=https://m2pool.com/zh><link rel=alternate hreflang=en href=https://m2pool.com/en><link rel=alternate hreflang=x-default href=https://m2pool.com/en><meta property=og:title content="M2pool - Stable leading high-yield mining pool"><meta property=og:description content="M2Pool provides professional mining services, supporting multiple cryptocurrency mining"><meta property=og:url content=https://m2pool.com/en><meta property=og:site_name content=M2Pool><meta property=og:type content=website><meta property=og:image content=https://m2pool.com/logo.png><link rel=icon href=/favicon.ico><link rel=stylesheet href=//at.alicdn.com/t/c/font_4582735_7i8wfzc0art.css><title>M2pool - Stable leading high-yield mining pool</title><meta name=keywords content="M2Pool, cryptocurrency mining pool,Entropyx(enx),entropyx, bitcoin mining, DGB mining, mining pool service, 加密货币矿池, 比特币挖矿, DGB挖矿"><meta name=description content="M2Pool provides professional mining services, supporting multiple cryptocurrency mining, including nexa, grs, mona, dgb, rxd, enx"><meta name=format-detection content="telephone=no"><meta name=apple-mobile-web-app-capable content=yes><script defer src=/js/chunk-vendors-945ce2fe.648a91a9.js></script><script defer src=/js/chunk-vendors-aacc2dbb.d317c558.js></script><script defer src=/js/chunk-vendors-bc050c32.3f2f14d2.js></script><script defer src=/js/chunk-vendors-3003db77.d0b93d36.js></script><script defer src=/js/chunk-vendors-9d134daf.bb668c99.js></script><script defer src=/js/chunk-vendors-439af1fa.48a48f35.js></script><script defer src=/js/chunk-vendors-5c533fba.b9c00e08.js></script><script defer src=/js/chunk-vendors-96cecd74.a7d9b845.js></script><script defer src=/js/chunk-vendors-c2f7d60e.3710fdc2.js></script><script defer src=/js/chunk-vendors-89d5c698.2190b4ca.js></script><script defer src=/js/chunk-vendors-377fed06.159de137.js></script><script defer src=/js/chunk-vendors-5a805870.4cfc0ae8.js></script><script defer src=/js/chunk-vendors-cf2e0a28.c6e99da0.js></script><script defer src=/js/app-42f9d7e6.f413248c.js></script><script defer src=/js/app-d363ae0c.ec582e15.js></script><script defer src=/js/app-5c551db8.6b412dd5.js></script><script defer src=/js/app-01dc9ae1.e746f05c.js></script><script defer src=/js/app-8e0489d9.3811f71f.js></script><script defer src=/js/app-72600b29.11174efb.js></script><script defer src=/js/app-f035d474.92e1d288.js></script><script defer src=/js/app-113c6c50.56b97e4e.js></script><link href=/css/chunk-vendors-5c533fba.6f97509c.css rel=stylesheet><link href=/css/app-189e7968.908e0479.css rel=stylesheet><link href=/css/app-01dc9ae1.04da7d85.css rel=stylesheet><link href=/css/app-8e0489d9.c5f430f0.css rel=stylesheet><link href=/css/app-72600b29.37eab263.css rel=stylesheet><link href=/css/app-f035d474.0348646a.css rel=stylesheet><link href=/css/app-113c6c50.dfa1d227.css rel=stylesheet></head><body><div id=app></div></body></html>
|
||||||
1
mining-pool/test/js/app-42f9d7e6.f413248c.js
Normal file
1
mining-pool/test/js/app-42f9d7e6.f413248c.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-42f9d7e6.f413248c.js.gz
Normal file
BIN
mining-pool/test/js/app-42f9d7e6.f413248c.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-5c551db8.6b412dd5.js
Normal file
1
mining-pool/test/js/app-5c551db8.6b412dd5.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-5c551db8.6b412dd5.js.gz
Normal file
BIN
mining-pool/test/js/app-5c551db8.6b412dd5.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-72600b29.11174efb.js
Normal file
1
mining-pool/test/js/app-72600b29.11174efb.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-72600b29.11174efb.js.gz
Normal file
BIN
mining-pool/test/js/app-72600b29.11174efb.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-8e0489d9.3811f71f.js
Normal file
1
mining-pool/test/js/app-8e0489d9.3811f71f.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-8e0489d9.3811f71f.js.gz
Normal file
BIN
mining-pool/test/js/app-8e0489d9.3811f71f.js.gz
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"><url><loc>https://m2pool.com/en</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>daily</changefreq><priority>1.0</priority></url><url><loc>https://m2pool.com/en/dataDisplay</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://m2pool.com/en/ServiceTerms</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>monthly</changefreq><priority>0.6</priority></url><url><loc>https://m2pool.com/en/apiFile</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/rate</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/nexaAccess</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/grsAccess</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/monaAccess</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgbsAccess</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgbqAccess</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgboAccess</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/rxdAccess</loc><lastmod>2025-06-13T06:54:37.634Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url></urlset>
|
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"><url><loc>https://m2pool.com/en</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>daily</changefreq><priority>1.0</priority></url><url><loc>https://m2pool.com/en/dataDisplay</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://m2pool.com/en/ServiceTerms</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>monthly</changefreq><priority>0.6</priority></url><url><loc>https://m2pool.com/en/apiFile</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/rate</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/nexaAccess</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/grsAccess</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/monaAccess</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgbsAccess</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgbqAccess</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgboAccess</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/rxdAccess</loc><lastmod>2025-06-17T02:57:34.126Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url></urlset>
|
||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"><url><loc>https://m2pool.com/zh</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/dataDisplay</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/ServiceTerms</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/apiFile</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/rate</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/nexaAccess</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/grsAccess</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/monaAccess</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgbsAccess</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgbqAccess</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgboAccess</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/rxdAccess</loc><lastmod>2025-06-13T06:54:37.623Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url></urlset>
|
<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"><url><loc>https://m2pool.com/zh</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/dataDisplay</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/ServiceTerms</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/apiFile</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/rate</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/nexaAccess</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/grsAccess</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/monaAccess</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgbsAccess</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgbqAccess</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgboAccess</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/rxdAccess</loc><lastmod>2025-06-17T02:57:34.114Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url></urlset>
|
||||||
Binary file not shown.
Reference in New Issue
Block a user