diff --git a/mining-pool/src/App.vue b/mining-pool/src/App.vue
index 56549b4..3519071 100644
--- a/mining-pool/src/App.vue
+++ b/mining-pool/src/App.vue
@@ -1,7 +1,7 @@
-
+
+ },
+ mounted() {
+ document.addEventListener("click", this.handleClickOutside);
+ // 添加聊天窗口滚动监听
+ this.$nextTick(() => {
+ if (this.$refs.chatBody) {
+ this.$refs.chatBody.addEventListener("scroll", this.handleChatScroll);
+ }
+ });
+
+ // 添加页面可见性变化监听
+ document.addEventListener("visibilitychange", this.handleVisibilityChange);
+ },
+ methods: {
+ // 处理页面可见性变化
+ handleVisibilityChange() {
+ // 当页面变为可见且聊天窗口已打开时,标记消息为已读
+ if (!document.hidden && this.isChatOpen && this.roomId) {
+ this.markMessagesAsRead();
+ }
+ },
+
+ // 标记消息为已读
+ async markMessagesAsRead() {
+ try {
+ const data = {
+ roomId: this.roomId
+ };
+
+ const response = await getReadMessage(data);
+
+ if (response && response.code === 200) {
+ console.log('消息已标记为已读');
+ // 清除未读消息计数
+ this.unreadMessages = 0;
+ // 更新所有用户消息的已读状态
+ this.messages.forEach(msg => {
+ if (msg.type === 'user') {
+ msg.isRead = true;
+ }
+ });
+ } else {
+ console.warn('标记消息已读失败', response);
+ }
+ } catch (error) {
+ console.error('标记消息已读出错:', error);
+ }
+ },
+
+ // 加载历史消息
+ async loadHistoryMessages() {
+ if (this.isLoadingHistory || !this.hasMoreHistory || !this.roomId) return;
+
+ this.isLoadingHistory = true;
+
+ try {
+ // 显示加载中提示
+ const loadingMsg = {
+ type: "system",
+ text: "正在加载历史消息...",
+ isLoading: true,
+ time: new Date(),
+ };
+ this.messages.unshift(loadingMsg);
+
+ // 获取7天内的最新聊天记录,传入 roomId
+ const response = await getHistory7({ roomId: this.roomId });
+
+ // 移除加载中提示
+ this.messages = this.messages.filter((msg) => !msg.isLoading);
+
+ if (response && response.code === 200 && response.data && response.data.length > 0) {
+ // 处理并添加历史消息
+ const historyMessages = this.formatHistoryMessages(response.data);
+
+ // 将历史消息添加到消息列表的前面
+ this.messages = [...historyMessages, ...this.messages];
+
+ // 设置是否还有更多历史消息
+ this.hasMoreHistory = historyMessages.length > 0;
+ } else {
+ // 添加提示信息
+ this.messages.unshift({
+ type: "system",
+ text: "暂无最近的聊天记录",
+ isSystemHint: true,
+ time: new Date(),
+ });
+ this.hasMoreHistory = false;
+ }
+ } catch (error) {
+ console.error("加载历史消息失败:", error);
+ // 添加错误提示
+ this.messages.unshift({
+ type: "system",
+ text: "加载历史消息失败,请重试",
+ isError: true,
+ time: new Date(),
+ });
+ } finally {
+ this.isLoadingHistory = false;
+ }
+ },
+
+ // 加载更多历史消息(超过7天的)
+ async loadMoreHistory() {
+ if (this.isLoadingHistory || !this.roomId) return;
+
+ this.isLoadingHistory = true;
+
+ try {
+ // 显示加载中提示
+ const loadingMsg = {
+ type: "system",
+ text: "正在加载更多历史消息...",
+ isLoading: true,
+ time: new Date(),
+ };
+ this.messages.unshift(loadingMsg);
+
+ // 获取更早的聊天记录,传入 roomId
+ const response = await getHistory({ roomId: this.roomId });
+
+ // 移除加载中提示
+ this.messages = this.messages.filter((msg) => !msg.isLoading);
+
+ if (response && response.code === 200 && response.data && response.data.length > 0) {
+ // 处理并添加历史消息
+ const historyMessages = this.formatHistoryMessages(response.data);
+
+ // 将历史消息添加到消息列表的前面
+ this.messages = [...historyMessages, ...this.messages];
+
+ // 如果没有数据返回,表示没有更多历史记录
+ this.hasMoreHistory = historyMessages.length > 0;
+
+ 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.messages.unshift({
+ type: "system",
+ text: "加载更多历史消息失败",
+ isError: true,
+ time: new Date(),
+ });
+ } finally {
+ this.isLoadingHistory = false;
+ }
+ },
+
+ // 格式化历史消息数据
+ formatHistoryMessages(messagesData) {
+ if (!messagesData || !Array.isArray(messagesData)) return [];
+
+ return messagesData
+ .map((msg) => {
+ const isSelf =
+ msg.sendUserType === this.userType &&
+ msg.sendUserEmail === this.userEmail;
+
+ return {
+ type: isSelf ? "user" : "system",
+ text: msg.content || "",
+ isImage: msg.type === 1 || msg.type === "image",
+ imageUrl:
+ msg.type === 1 || msg.type === "image" ? msg.content : null,
+ time: msg.timestamp ? new Date(msg.timestamp) : new Date(),
+ id: msg.id,
+ roomId: msg.roomId,
+ sendUserType: msg.sendUserType,
+ isHistory: true, // 标记为历史消息
+ isRead: msg.isRead || true, // 历史消息默认已读
+ };
+ })
+ .sort((a, b) => a.time - b.time); // 按时间排序
+},
+
+
+ // 修改 fetchUserid 方法,使其返回 Promise
+ async fetchUserid() {
+ try {
+ const res = await getUserid();
+ if (res && res.code == 200) {
+ console.log('获取用户ID成功:', res);
+ this.receivingEmail = res.data.userEmail;
+ this.roomId = res.data.id;
+ return res.data;
+ } else {
+ console.warn('获取用户ID未返回有效数据');
+ return null;
+ }
+ } catch (error) {
+ console.error('获取用户ID失败:', error);
+ throw error;
+ }
+ },
+
+ // 初始化 WebSocket 连接
+ initWebSocket() {
+ this.determineUserType();
+ this.connectWebSocket();
+ },
+
+ // 确定用户类型和邮箱
+ determineUserType() {
+ try {
+ const token = JSON.parse(localStorage.getItem("token") || "{}");
+ const userInfo = JSON.parse(
+ localStorage.getItem("jurisdiction") || "{}"
+ );
+ const email = JSON.parse(localStorage.getItem("userEmail") || "{}");
+ if (token) {
+ if (userInfo.roleKey === "customer_service") {
+ // 客服用户
+ this.userType = 2;
+ } else {
+ // 登录用户
+ this.userType = 1;
+ }
+ this.userEmail = email;
+ } else {
+ //游客
+ 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
+ connectWebSocket() {
+ this.connectionStatus = "connecting";
+
+ try {
+ const wsUrl = `${process.env.VUE_APP_BASE_API}chat/ws`;
+
+ // 创建 STOMP 客户端
+ this.stompClient = new Client({
+ brokerURL: wsUrl,
+ connectHeaders: {
+ email: this.userEmail,
+ type: this.userType,
+ },
+ debug: function (str) {
+ console.log("STOMP: " + str);
+ },
+ reconnectDelay: 5000,
+ heartbeatIncoming: 4000,
+ heartbeatOutgoing: 4000,
+ });
+
+ // 连接成功回调
+ this.stompClient.onConnect = (frame) => {
+ console.log("连接成功: " + frame);
+ this.connectionStatus = "connected";
+
+ // 订阅个人消息频道
+ this.stompClient.subscribe(
+ `${process.env.VUE_APP_BASE_API}user/queue/${this.userEmail}`,
+ this.onMessageReceived
+ );
+
+ // 根据用户类型显示不同的欢迎消息
+ let welcomeMessage = "";
+ switch (this.userType) {
+ case 0:
+ welcomeMessage = "您当前以游客身份访问,请问有什么可以帮您?";
+ break;
+ case 1:
+ welcomeMessage = "欢迎回来,请问有什么可以帮您?";
+ break;
+ case 2:
+ welcomeMessage = "您已以客服身份登录系统";
+ break;
+ }
+ this.addSystemMessage(welcomeMessage);
+ };
+
+ // 连接错误回调
+ this.stompClient.onStompError = (frame) => {
+ console.error("连接错误: " + frame.headers.message);
+ this.connectionStatus = "error";
+ this.addSystemMessage("连接客服系统失败,请稍后重试。");
+ };
+
+ // 启动连接
+ this.stompClient.activate();
+ } catch (error) {
+ console.error("初始化 WebSocket 失败:", error);
+ this.connectionStatus = "error";
+ }
+ },
+
+ // 断开 WebSocket 连接
+ disconnectWebSocket() {
+ if (this.stompClient && this.stompClient.connected) {
+ this.stompClient.deactivate();
+ this.connectionStatus = "disconnected";
+ }
+ },
+
+ // 添加新方法:更新消息已读状态
+updateMessageReadStatus(messageIds) {
+ if (!Array.isArray(messageIds) || messageIds.length === 0) {
+ // 如果没有具体的消息ID,就更新所有用户消息为已读
+ this.messages.forEach(msg => {
+ if (msg.type === 'user') {
+ msg.isRead = true;
+ }
+ });
+ } else {
+ // 更新指定ID的消息为已读
+ this.messages.forEach(msg => {
+ if (msg.id && messageIds.includes(msg.id)) {
+ msg.isRead = true;
+ }
+ });
+ }
+},
+
+ // 接收消息处理
+ onMessageReceived(message) {
+ console.log("收到消息:", message.body);
+ try {
+ const data = JSON.parse(message.body);
+
+ // 处理已读回执消息
+ if (data.type === 'read_receipt') {
+ // 更新对应消息的已读状态
+ this.updateMessageReadStatus(data.messageIds || []);
+ return;
+ }
+
+ // 添加客服消息
+ this.messages.push({
+ type: "system",
+ text: data.content,
+ isImage: data.type === "image",
+ imageUrl: data.type === "image" ? data.content : null,
+ time: new Date(),
+ roomId: data.roomId || this.roomId,
+ });
+
+ // 如果聊天窗口已打开,标记为已读
+ if (this.isChatOpen && this.roomId) {
+ this.markMessagesAsRead();
+ } else {
+ // 如果聊天窗口没有打开,显示未读消息数
+ this.unreadMessages++;
+ }
+
+ this.$nextTick(() => {
+ this.scrollToBottom();
+ });
+ } catch (error) {
+ console.error("解析消息失败:", error);
+ }
+},
+
+ // 切换聊天窗口
+ async toggleChat() {
+ this.isChatOpen = !this.isChatOpen;
+
+ if (this.isChatOpen) {
+ this.unreadMessages = 0;
+
+ try {
+ // 先获取用户ID,等待完成
+ await this.fetchUserid();
+
+ // 如果未连接,则连接 WebSocket
+ if (this.connectionStatus === "disconnected") {
+ this.initWebSocket();
+ }
+
+ // 获取到 roomId 后才查询历史消息
+ if (this.roomId && this.messages.length === 0) {
+ this.loadHistoryMessages();
+ }
+
+ // 新增:标记消息为已读
+ if (this.roomId) {
+ this.markMessagesAsRead();
+ }
+
+ this.$nextTick(() => {
+ this.scrollToBottom();
+ });
+ } catch (error) {
+ console.error('初始化聊天失败:', error);
+ }
+ }
+ },
+
+ minimizeChat() {
+ this.isChatOpen = false;
+ },
+
+ closeChat() {
+ this.isChatOpen = false;
+ this.messages = [];
+ this.disconnectWebSocket();
+ },
+
+ // 发送消息
+ sendMessage() {
+ if (!this.inputMessage.trim() || this.connectionStatus !== "connected")
+ return;
+
+ const messageText = this.inputMessage.trim();
+
+ // 添加用户消息到界面
+ this.messages.push({
+ type: "user",
+ text: messageText,
+ time: new Date(),
+ email: this.receivingEmail,
+ sendUserType: this.userType,
+ roomId: this.roomId,
+ isRead: false, // 新发送的消息默认未读
+ });
+
+ // 通过 WebSocket 发送消息
+ if (this.stompClient && this.stompClient.connected) {
+ this.stompClient.publish({
+ destination: "/send/message",
+ body: JSON.stringify({
+ content: messageText,
+ type: 0,
+ email: this.receivingEmail,
+ sendUserType: this.userType,
+ roomId: this.roomId,
+ }),
+ });
+ } else {
+ this.handleAutoResponse(messageText);
+ }
+
+ this.inputMessage = "";
+
+ this.$nextTick(() => {
+ this.scrollToBottom();
+ });
+},
+
+ // 添加系统消息
+ addSystemMessage(text) {
+ this.messages.push({
+ type: "system",
+ text: text,
+ isImage: false,
+ time: new Date(),
+ });
+
+ // 滚动到底部
+ this.$nextTick(() => {
+ this.scrollToBottom();
+ });
+ },
+
+ // 自动回复 (仅在无法连接服务器时使用)
+ handleAutoResponse(message) {
+ setTimeout(() => {
+ let response =
+ "抱歉,我暂时无法回答这个问题。请排队等待人工客服或提交工单。";
+
+ // 检查是否匹配自动回复关键词
+ for (const [keyword, reply] of Object.entries(this.autoResponses)) {
+ if (message.toLowerCase().includes(keyword.toLowerCase())) {
+ response = reply;
+ break;
+ }
+ }
+
+ // 添加系统回复
+ this.messages.push({
+ type: "system",
+ text: response,
+ isImage: false,
+ time: new Date(),
+ });
+
+ if (!this.isChatOpen) {
+ this.unreadMessages++;
+ }
+
+ this.$nextTick(() => {
+ this.scrollToBottom();
+ });
+ }, 1000);
+ },
+
+ // 滚动到消息列表顶部检测,用于加载更多历史消息
+ handleChatScroll() {
+ if (!this.$refs.chatBody) return;
+
+ const { scrollTop } = this.$refs.chatBody;
+ // 当滚动到顶部时,加载更多历史消息
+ if (scrollTop < 50 && this.hasMoreHistory && !this.isLoadingHistory) {
+ this.loadMoreHistory();
+ }
+ },
+
+ scrollToBottom() {
+ if (this.$refs.chatBody) {
+ this.$refs.chatBody.scrollTop = this.$refs.chatBody.scrollHeight;
+ }
+ },
+
+ formatTime(date) {
+ return date.toLocaleTimeString([], {
+ hour: "2-digit",
+ minute: "2-digit",
+ });
+ },
+
+ handleClickOutside(event) {
+ if (this.isChatOpen) {
+ const chatElement = this.$el.querySelector(".chat-dialog");
+ const chatIcon = this.$el.querySelector(".chat-icon");
+
+ if (
+ chatElement &&
+ !chatElement.contains(event.target) &&
+ !chatIcon.contains(event.target)
+ ) {
+ this.isChatOpen = false;
+ }
+ }
+ },
+
+ // 处理图片上传
+ handleImageUpload(event) {
+ if (this.connectionStatus !== "connected") return;
+
+ const file = event.target.files[0];
+ if (!file) return;
+
+ // 检查是否为图片
+ if (!file.type.startsWith("image/")) {
+ this.$message({
+ message: this.$t("chat.onlyImages") || "只能上传图片文件!",
+ type: "warning",
+ });
+ return;
+ }
+
+ // 检查文件大小 (限制为5MB)
+ const maxSize = 5 * 1024 * 1024;
+ if (file.size > maxSize) {
+ this.$message({
+ message: this.$t("chat.imageTooLarge") || "图片大小不能超过5MB!",
+ type: "warning",
+ });
+ return;
+ }
+
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ const imageUrl = e.target.result;
+
+ // 添加用户图片消息到界面
+ this.messages.push({
+ type: "user", // 修改为 "user" 以符合消息类型格式
+ text: "",
+ isImage: true,
+ imageUrl: imageUrl,
+ time: new Date(),
+ email: this.receivingEmail, // 接收者邮箱
+ sendUserType: this.userType, // 发送者类型
+ roomId: this.roomId, // 聊天室ID
+ isRead: false, // 新发送的图片消息默认未读
+ });
+
+ // 通过 WebSocket 发送图片消息
+ if (this.stompClient && this.stompClient.connected) {
+ this.stompClient.publish({
+ destination: "/send/message",
+ body: JSON.stringify({
+ content: imageUrl,
+ type: "image",
+ email: this.receivingEmail,
+ sendUserType: this.userType,
+ roomId: this.roomId
+ }),
+ });
+ }
+
+ this.$nextTick(() => {
+ this.scrollToBottom();
+ });
+ };
+
+ reader.readAsDataURL(file);
+ this.$refs.imageUpload.value = "";
+ },
+
+ // 预览图片
+ previewImage(imageUrl) {
+ this.previewImageUrl = imageUrl;
+ this.showImagePreview = true;
+ },
+
+ // 关闭图片预览
+ closeImagePreview() {
+ this.showImagePreview = false;
+ this.previewImageUrl = "";
+ },
+ },
+
+ beforeDestroy() {
+ this.disconnectWebSocket();
+ document.removeEventListener("click", this.handleClickOutside);
+ // 移除滚动监听
+ if (this.$refs.chatBody) {
+ this.$refs.chatBody.removeEventListener("scroll", this.handleChatScroll);
+ }
+ // 移除页面可见性变化监听
+ document.removeEventListener("visibilitychange", this.handleVisibilityChange);
+ },
+};
+
\ No newline at end of file
+}
+
+
+
+.message-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 4px;
+ font-size: 11px;
+}
+
+.message-time {
+ color: #999;
+}
+
+.message-read-status {
+ color: #999;
+ font-size: 10px;
+ margin-left: 5px;
+}
+
+.chat-message-user .message-read-status {
+ color: rgba(255, 255, 255, 0.7);
+}
+
\ No newline at end of file
diff --git a/mining-pool/src/main.js b/mining-pool/src/main.js
index 0c37564..d79dae9 100644
--- a/mining-pool/src/main.js
+++ b/mining-pool/src/main.js
@@ -23,7 +23,7 @@ Vue.use(ElementUI, {
});
Vue.prototype.$axios = axios
-console.log = ()=>{} //全局关闭打印
+// console.log = ()=>{} //全局关闭打印
// 全局注册混入
Vue.mixin(loadingStateMixin);
Vue.mixin(networkRecoveryMixin);
diff --git a/mining-pool/src/views/customerService/index.vue b/mining-pool/src/views/customerService/index.vue
index 13caa90..c9736e0 100644
--- a/mining-pool/src/views/customerService/index.vue
+++ b/mining-pool/src/views/customerService/index.vue
@@ -250,10 +250,12 @@ export default {
try {
this.loadingRooms = true;
const response = await getRoomList();
- if (response && response.code === 200 && response.data) {
- this.contacts = response.data.map(room => ({
- roomId: room.roomId,
- name: room.roomName || '未命名聊天室',
+
+ console.log(response,"获取聊天室列表");
+ if (response && response.code === 200 ) {
+ this.contacts = response.rows.map(room => ({
+ roomId: room.id,
+ name: room.userEmail || '未命名聊天室',
avatar: this.getDefaultAvatar(room.roomName || '未命名聊天室'), // 使用默认头像
lastMessage: room.lastMessage || '暂无消息',
lastTime: room.lastTime || new Date(),
diff --git a/mining-pool/src/views/home/index.js b/mining-pool/src/views/home/index.js
index a19fa35..348c381 100644
--- a/mining-pool/src/views/home/index.js
+++ b/mining-pool/src/views/home/index.js
@@ -978,61 +978,7 @@ export default {
}, 200),
- // async getPoolPowerData(params) {
- // this.minerChartLoading = true
- // const data = await getPoolPower(params)
- // if (!data) {
- // this.minerChartLoading = false
- // if (this.myChart) {
- // this.myChart.dispose()//销毁图表实列
- // }
- // return
- // }
- // let chartData = data.data
- // let xData = []
- // let pvData = []
- // let rejectRate = []
- // let price = []
- // chartData.forEach(item => {
-
- // if (item.date.includes(`T`) && params.interval == `rt`) {
-
- // item.date = `${item.date.split("T")[0]} ${item.date.split("T")[1].split(`.`)[0]}`
- // } else if (item.date.includes(`T`) && params.interval == `1d`) {
- // item.date = item.date.split("T")[0]
- // }
-
-
- // xData.push(item.date)
- // pvData.push(Number(item.pv).toFixed(2))
- // // rejectRate.push((item.rejectRate * 100).toFixed(2))
- // if (item.price == 0) {
- // price.push(item.price)
- // } else if (item.price < 1) {
- // price.push(Number(item.price).toFixed(8))
-
- // } else {
- // price.push(Number(item.price).toFixed(2))
- // }
-
-
-
- // });
- // // this.maxValue = Math.max(...rejectRate);
- // // let leftYMaxData = Math.max(...pvData);
- // // this.option.yAxis[0].max =leftYMaxData*2
- // this.option.xAxis.data = xData
- // this.option.series[0].data = pvData
- // // this.option.series[1].data = rejectRate
- // this.option.series[1].data = price
- // this.$nextTick(() => {
- // this.inCharts()
- // })
-
-
-
-
- // },
+
getPoolPowerData: Debounce(async function (params) {
// this.minerChartLoading = true
this.setLoading('minerChartLoading', true);