diff --git a/mining-pool/.env.development b/mining-pool/.env.development index 40adac6..9f360fd 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/dist.zip b/mining-pool/dist.zip index c482dde..8fb5a34 100644 Binary files a/mining-pool/dist.zip and b/mining-pool/dist.zip differ diff --git a/mining-pool/src/App.vue b/mining-pool/src/App.vue index c9353a5..805b156 100644 --- a/mining-pool/src/App.vue +++ b/mining-pool/src/App.vue @@ -1,7 +1,7 @@ @@ -1351,6 +3522,16 @@ export default { } } + &.disconnected { + i { + color: #f39c12; + } + + p { + color: #f39c12; + } + } + .retry-button { margin-top: 16px; padding: 8px 16px; @@ -1416,9 +3597,24 @@ export default { } .message-content { + position: relative; max-width: 70%; - padding: 10px 15px; + padding: 18px 15px 10px 15px; // 上方多留空间给时间 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + + .message-time { + position: absolute; + top: 6px; + right: 15px; + font-size: 11px; + color: #bbb; + pointer-events: none; + user-select: none; + } + // 用户消息气泡内时间颜色适配 + .chat-message-user & .message-time { + color: rgba(255, 255, 255, 0.7); + } } .message-text { @@ -1664,4 +3860,118 @@ export default { .chat-message-user .message-read-status { color: rgba(255, 255, 255, 0.7); } + +.network-status { + position: fixed; + top: 80px; + right: 20px; + padding: 8px 16px; + border-radius: 4px; + display: flex; + align-items: center; + gap: 8px; + z-index: 1000; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); + background-color: #fef0f0; + color: #f56c6c; +} + +.guest-notice { + background-color: #f8f9fa; + border-radius: 8px; + padding: 8px 12px; + margin-bottom: 10px; + text-align: center; + border: 1px solid #e0e0e0; + + .guest-notice-content { + display: inline-flex; + gap: 2px; + color: #666; + font-size: 13px; + line-height: 1.4; + + i { + color: #ac85e0; + font-size: 16px; + flex-shrink: 0; + } + + .login-link { + color: #ac85e0; + text-decoration: none; + font-weight: bold; + cursor: pointer; + transition: color 0.3s; + margin: 0 2px; + + &:hover { + color: #6e3edb; + text-decoration: underline; + } + } + } +} + +.error-actions { + display: flex; + gap: 10px; + margin-top: 16px; + justify-content: center; + + .retry-button, + .refresh-button { + padding: 8px 16px; + border: none; + border-radius: 20px; + cursor: pointer; + font-weight: bold; + transition: all 0.3s ease; + + &:hover { + transform: translateY(-1px); + } + } + + .retry-button { + background-color: #ac85e0; + color: white; + + &:hover { + background-color: #6e3edb; + } + } + + .refresh-button { + background-color: #f0f0f0; + color: #666; + padding: 0px 16px; + + &:hover { + background-color: #e0e0e0; + } + } +} + +.chat-time-divider { + text-align: center; + margin: 16px 0; + font-size: 12px; + color: #fff; + background: rgba(180, 180, 180, 0.6); + display: inline-block; + padding: 2px 12px; + border-radius: 10px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); + left: 50%; + transform: translateX(-50%); + position: relative; +} + +/* === 移除本地消息的视觉反馈(小黄点) === */ +/* .chat-message-local { + // 不再显示任何特殊样式 +} */ + + \ No newline at end of file diff --git a/mining-pool/src/components/header.vue b/mining-pool/src/components/header.vue index 182d3f3..fdfcf4c 100644 --- a/mining-pool/src/components/header.vue +++ b/mining-pool/src/components/header.vue @@ -382,10 +382,15 @@ export default { document.addEventListener("click", function () { const dropdown = document.querySelector(".dropdown"); const arrow = document.querySelector(".arrow"); - if (dropdown.classList.contains("show")) { + try { + if (dropdown.classList.contains("show")) { dropdown.classList.remove("show"); arrow.classList.remove("up"); } + } catch (error) { + console.log(error) + } + }); @@ -445,6 +450,8 @@ export default { async fetchSignOut() { const data = await getLogout(); if (data && data.code == 200) { + // 调用 Vuex 的 logout action 清除前端状态 + await this.$store.dispatch('logout') const lang = this.$i18n.locale; this.$router.push(`/${lang}`); } @@ -695,8 +702,11 @@ export default { justify-content: center; } + + .miningAccountTitle:hover { color: #6e3edb !important; + } .hidden { display: block; diff --git a/mining-pool/src/i18n/ChatWidget.js b/mining-pool/src/i18n/ChatWidget.js index ef2b1e3..81d2e2e 100644 --- a/mining-pool/src/i18n/ChatWidget.js +++ b/mining-pool/src/i18n/ChatWidget.js @@ -10,7 +10,104 @@ export const ChatWidget_zh = { onlyImages:"只能上传图片文件!", imageTooLarge:"图片大小不能超过5MB!", imageReceived:"已收到您的图片,我们会尽快处理您的问题。", - }, + + networkError:"网络连接已断开,请刷新页面重试", + openCustomerService:"打开客服聊天", + connectToCustomerService:"正在连接客服系统...", + connectionFailed:"连接失败,请刷新页面重试", + tryConnectingAgain:"重试连接", + loading:"加载中...", + loadMore:"加载更多历史消息", + welcomeToUse:"欢迎使用在线客服,请问有什么可以帮您?", + picture:"聊天图片", + read:"已读", + unread:"未读", + subscriptionFailed:"消息订阅失败,可能无法接收新消息", + break:"连接断开", + retry:"秒后重试", + disconnectWaiting:"断线重连中...", + sendFailed:"发送消息失败,请重试", + noHistory:"暂无历史消息", + historicalFailure:"加载历史消息失败,请重试", + loadingHistory:"正在加载更多历史消息...", + noMoreHistory:"没有更多历史消息了", + Loaded:"已加载历史消息", + newMessage:"新消息", + pictureMessage:"图片消息", + initializationFailed:"初始化失败,请刷新页面重试", + beSorry:"抱歉,我暂时无法回答这个问题。请排队等待人工客服或提交工单。", + today:"今天", + yesterday:"昨天", + canOnlyUploadImages:"只能上传图片文件!", + imageSizeExceeded:"图片大小不能超过5MB!", + uploading:"正在上传图片...", + pictureFailed:"发送图片失败,请重试", + readImage:"读取图片失败,请重试", + processingFailed:"图片处理失败,请重试", + Disconnected:"连接已断开", + reconnecting:"正在重连...", + contactList:"联系列表", + search:"搜索最近联系人", + tourist:"游客", + important:"重要", + markAsImportant:"标记为重要", + cancelImportant:"已取消重要标记", + markingFailed:"标记操作失败,请重试", + Marked:"已标记为重要", + select:"请选择联系人", + notSelected:"您尚未选择联系人", + None:"暂无消息记录", + sendPicture:"发送图片", + inputMessage:"请输入消息,按Enter键发送,按Ctrl+Enter键换行", + bottom:"回到底部", + Preview:"预览图片", + chatRoom:"聊天室", + CLOSED:"已关闭", + picture2:"图片", + Unnamed:"未命名聊天室", + noNewsAtTheMoment:"暂无未读消息", + contactFailed:"加载更多联系人失败", + listException:"获取聊天室列表异常", + my:"我", + unknownSender:"未知发送者", + recordFailed:"加载聊天记录失败", + messageException:"加载消息异常", + chooseFirst:"请先选择联系人", + chatDisconnected:"聊天连接已断开,请刷新页面重试", + pictureSuccessful:"图片已发送", + history:"历史记录", + loadFailed:"加载失败", + guestNotice:"您当前以游客身份聊天,聊天记录将不会保存。", + guestNotice2:"后即可保存聊天记录", + loginToSave:"登录", + server500:"服务器暂时不可用,请稍后重试", + CheckNetwork:"连接失败,请检查网络后重试", + attemptToReconnect:"连接已断开,正在尝试重连...", + retryFailed:"重试连接失败,请刷新页面", + maxConnectionsError:"连接数已达上限,请刷新页面重试", + ipLimitError:"本机连接数已达上限,请刷新页面重试", + serverLimitError:"服务器连接数已达上限,请稍后刷新重试", + identityError:"用户身份设置失败,请刷新页面重试", + emailError:"用户信息获取失败,请刷新页面重试", + refreshPage:"刷新页面", + reconnectSuccess:"重新连接成功", + sendMessageEmpty:"发送消息不能为空", + unableToSubscribe:"连接状态异常,刷新页面重试", + conflict:"连接异常,可能是多窗口冲突,请关闭其他窗口重试", + abnormal:"连接异常", + networkAnomaly:"网络连接异常", + customerServiceOffline:"客服离线,请登录账号发送留言消息", + contentMax:"超出发送内容大小限制,请删除部分内容(300字以内)", + failInSend:"发送失败,请重试", + connectionLimitError:"连接数已达上限,请关闭一些窗口后刷新重试", + serverBusy:"服务器繁忙,请稍后刷新重试", + connectionTimedOut:"连接超时,稍后重试...", + reconnectFailed:"重连失败,请稍后重试", + serviceConfigurationError:"服务配置异常,请稍后重试", + serviceAddressUnavailable:"服务地址不可用,请稍后重试", + connectionFailedService:"无法连接到服务器,请稍后重试", + connectionFailedCustomer:"连接客服系统失败,请检查网络或稍后重试", + }, } @@ -28,5 +125,111 @@ export const ChatWidget_en = { onlyImages:"Only image files can be uploaded!", imageTooLarge:"The image size cannot exceed 5MB!", imageReceived:"We have received your image, and we will handle your question as soon as possible.", - } + + networkError: "Network disconnected, please refresh page", + openCustomerService: "Open customer service chat", + connectToCustomerService: "Connecting to customer service...", + connectionFailed: "Connection failed, please refresh page", + tryConnectingAgain: "Retry connection", + loading: "Loading...", + loadMore: "Load more history", + welcomeToUse: "Welcome to online service, how can I help you?", + picture: "Chat image", + read: "Read", + unread: "Unread", + subscriptionFailed: "Message subscription failed", + break: "Connection lost", + retry: "Retry in seconds", + disconnectWaiting: "Reconnecting...", + sendFailed: "Send failed, please retry", + noHistory: "No history", + historicalFailure: "Failed to load history", + loadingHistory: "Loading more history...", + noMoreHistory: "No more history", + Loaded: "History loaded", + newMessage: "New message", + pictureMessage: "Image message", + initializationFailed: "Initialization failed, please refresh", + beSorry: "Sorry, I cannot answer this. Please wait for agent or submit ticket", + today: "Today", + yesterday: "Yesterday", + canOnlyUploadImages: "Only image files allowed", + imageSizeExceeded: "Image size exceeds 5MB", + uploading: "Uploading image...", + pictureFailed: "Failed to send image", + readImage: "Failed to read image", + processingFailed: "Image processing failed", + Disconnected: "Disconnected", + reconnecting: "Reconnecting...", + contactList: "Contact list", + search: "Search contacts", + tourist: "Guest", + important: "Important", + markAsImportant: "Mark as important", + cancelImportant: "Unmarked as important", + markingFailed: "Marking failed", + select: "Select contact", + notSelected: "No contact selected", + None: "No messages", + sendPicture: "Send image", + inputMessage: "Type message, Enter to send, Ctrl+Enter for new line", + bottom: "to bottom", + Preview: "Preview image", + chatRoom: "Chat room", + CLOSED: "Closed", + picture2: "Image", + Unnamed: "Unnamed chat", + noNewsAtTheMoment: "No unread messages", + contactFailed: "Failed to load contacts", + listException: "Failed to get chat list", + my: "Me", + unknownSender: "Unknown sender", + recordFailed: "Failed to load chat records", + messageException: "Failed to load messages", + chooseFirst: "Please select contact first", + chatDisconnected: "Chat disconnected, please refresh", + pictureSuccessful: "Image sent", + history:"History", + loadFailed:"Load Fail", + Marked:"Marked as important", + guestNotice:"You are currently chatting as a guest, and your chat history will not be saved.", + guestNotice2:" to save chat history", + loginToSave:"Login", + server500:"The server is temporarily unavailable, please try again later", + CheckNetwork:"Connection failed, please check the network and try again", + attemptToReconnect:"Connection lost, attempting to reconnect...", + retryFailed:"Retry connection failed, please refresh page", + maxConnectionsError:"Connection limit reached, please refresh page", + ipLimitError:"Connection limit reached, please refresh page", + serverLimitError:"Connection limit reached, please try again later", + identityError:"Failed to set user identity, please refresh page", + emailError:"Failed to get user information, please refresh page", + refreshPage:"Refresh page", + 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", + + + + + + + + + +} } \ No newline at end of file diff --git a/mining-pool/src/i18n/ServiceTerms.js b/mining-pool/src/i18n/ServiceTerms.js index 7ea2249..f797b31 100644 --- a/mining-pool/src/i18n/ServiceTerms.js +++ b/mining-pool/src/i18n/ServiceTerms.js @@ -9,7 +9,7 @@ export const serviceTerms_zh = { title2:"二、服务说明", clauseService1:"1.我们的服务旨在为用户提供数字货币挖矿相关的资源和支持,但不保证挖矿的收益或成功。", clauseService2:"2.服务可能会因维护、升级或其他原因而暂时中断,我们将尽力提前通知用户,但不对此类中断造成的损失负责。", - clauseService3:"3.M2Pool 不向以下司法管辖区的个人或实体提供服务:布隆迪、中非共和国、中国大陆、刚果、古巴、伊拉克、伊朗、朝鲜、黎巴嫩、利比亚、苏丹、索马里、南苏丹、叙利亚、也门和津巴布韦。", + clauseService3:"3.M2Pool 不向以下司法管辖区的个人或实体提供服务:阿富汗、白俄罗斯、中非共和国、刚果民主共和国、几内亚比绍、古巴、伊朗、伊拉克、朝鲜、利比亚、黎巴嫩、马里、叙利亚、委内瑞拉和津巴布韦。受限制的司法管辖区还包括M2pool选择不运营的任何国家/地区,包括但不限于阿尔及利亚、安哥拉、孟加拉国、中国、埃及、海地、科索沃、科威特、摩洛哥、俄罗斯、尼泊尔、索马里、南苏丹、苏丹、也门和新加坡。", clauseService4:" 通过访问和使用 M2Pool 服务,您声明并保证您不位于、不在上述任何国家/地区设立或不是上述任何国家的居民。M2Pool 保留自行决定限制或拒绝某些国家/地区提供服务的权利。如果 M2Pool 确定(自行决定)用户是指定国家/地区的居民,M2Pool 可能会冻结或终止这些帐户。", title3:"三、用户资格", clauseUser1:"1.您必须达到法定年龄并具备完全民事行为能力才能使用本服务。", @@ -52,7 +52,9 @@ export const serviceTerms_en = { "title": "Content of Service Terms", "title1": "1、 General Provisions", "clauseTotal1": "Welcome to the M2pool mining pool website (hereinafter referred to as \"this website\"). By using the services of this website (hereinafter referred to as the \"Services\"), you agree to comply with the following terms of service (hereinafter referred to as the \"Terms\").", "clauseTotal2": "2. Please carefully read the following terms. If you click the \"Register\" button or view or use these services, it is deemed that you have read and agreed to these terms of service and all its additional terms. If you do not accept the limitations of the terms of service, please do not view or use the service.", "clauseTotal3": "3. We reserve the right to modify these terms at any time, and the modified terms will be published on the website. By continuing to use the service, you accept the revised terms.", "clauseTotal4": "4. We hope that you can regularly review these terms to ensure that you have confirmed the terms and conditions applicable to your viewing and use. These terms and additional terms are available for your review and can be used to use any services we provide, including but not limited to the following websites: https://www.m2pool.com/ (hereinafter referred to as \"this website\").", "title2": "2、 Service Description", "clauseService1": "Our service aims to provide users with resources and support related to cryptocurrency mining, but we do not guarantee the profits or success of mining.", - "clauseService2": "2. The service may be temporarily interrupted due to maintenance, upgrades, or other reasons. We will do our best to notify users in advance, but we are not responsible for any losses caused by such interruptions.", "clauseService3": "3.M2Pool does not provide services to individuals or entities in the following jurisdictions: Burundi, Central African Republic, Chinese Mainland, Congo, Cuba, Iraq, Iran, North Korea, Lebanon, Libya, Sudan, Somalia, South Sudan, Syria, Yemen and Zimbabwe.", "clauseService4": "By accessing and using the M2Pool service, you declare and warrant that you are not located, established, or a resident of any of the aforementioned countries/regions. M2Pool reserves the right to restrict or refuse services provided by certain countries/regions at its own discretion. If M2Pool determines (at its discretion) that the user is a resident of a specified country/region, M2Pool may freeze or terminate these accounts.", "title3": "3、 User Qualification", + "clauseService2": "2. The service may be temporarily interrupted due to maintenance, upgrades, or other reasons. We will do our best to notify users in advance, but we are not responsible for any losses caused by such interruptions.", + "clauseService3": "3.M2Pool does not provide services to individuals or entities in the following jurisdictions: Afghanistan, Belarus, Central African Republic, Democratic Republic of the Congo, Guinea Bissau, Cuba, Iran, Iraq, North Korea, Libya, Lebanon, Mali, Syria, Venezuela and Zimbabwe. Restricted jurisdictions also include any country/territory in which M2pool chooses not to operate, including but not limited to Algeria, Angola, Bangladesh, China, Egypt, Haiti, Kosovo, Kuwait, Morocco, Russia, Nepal, Somalia, South Sudan, Sudan, Yemen and Singapore.", + "title3": "3、 User Qualification", "clauseUser1": "1. You must be of legal age and have full capacity for civil conduct to use this service.", "clauseUser2": "2. You guarantee that the registration information provided is true, accurate, complete, and updated in a timely manner. You can log in to M2Pool using other methods allowed by our email address. If the registration information you provide is incorrect, we will not be held responsible. You will suffer any direct or indirect losses and adverse consequences.", "clauseUser3": "3. You should be a legal person, company, or other organization with full capacity for conduct and civil rights. Otherwise, you or your guardian shall bear all consequences. We have the right to cancel or permanently suspend your account and demand compensation from you.", "title4": "4、 User Responsibility", "clauseResponsibility1": "1. You shall comply with all applicable national laws, regulations and normative documents, as well as the provisions and requirements of these rules, including but not limited to laws related to digital currency mining. Not violating the public interest or public morality, not harming the legitimate rights and interests of others, not evading taxes, and not violating these regulations and related rules. If you violate the above commitments and incur any legal consequences, you shall bear all legal responsibilities on your own and ensure that we are free from any losses.", "clauseResponsibility2": "2. You are not allowed to engage in any illegal, fraudulent, harmful, or infringing activities using this service.", "clauseResponsibility3": "3. You are responsible for your mining equipment and network connection, ensuring that it meets relevant requirements and operates normally.", "clauseResponsibility4": "4. You are responsible for the confidentiality of your M2Pool username and password, as well as all activities that occur under your username and M2Pool password (including but not limited to information disclosure and publication, online click to agree or submit various rules and agreements, online agreement renewal or purchase of services, account settings, etc.).", "clauseResponsibility5": "5. If anyone uses your M2pool email, account, etc. to log in to this website without authentication, we will not be responsible for any losses caused by your violation of these terms.", "title5": "5、 Fees and Payment", "clausePayment1": "We may charge a certain fee based on the service content, and the specific fee standard will be announced on the website.", "clausePayment2": "2. You agree to pay the fees according to the prescribed payment method and time. Failure to pay on time may result in the suspension or termination of the service.", "clausePayment3": "3. The taxable amount and all hardware, software, service or other expenses incurred by you when using this service shall be borne by you.", "title6": "6、 Income and distribution", "clauseProfit1": "1. Mining profits will be distributed according to our distribution mechanism, but we do not guarantee the stability and stability of the profits.", "clauseProfit2": "2. We have the right to adjust the allocation mechanism according to the actual situation, but we will notify users in advance.", "title7": "7、 Data and Privacy", "clausePrivacy1": "1. We will collect and use relevant data generated during your use of the service, but we will strictly comply with the privacy policy to protect your privacy.", "clausePrivacy2": "2. You agree to our collection, use, and processing of data to provide and improve services.", "title8": "8、 Intellectual Property", "clausePropertyRight1": "All content on this website, including but not limited to trademarks, copyrights, patents, etc., belongs to our company or relevant rights holders.", "clausePropertyRight2": "2. Without authorization, you are not allowed to copy, modify, disseminate or use any intellectual property of this website.", "title9": "9、 Disclaimer", "clauseDisclaimer1": "We are not responsible for service interruptions or data loss caused by force majeure, system failures, network issues, etc.", "clauseDisclaimer2": "2. We are not liable for any direct, indirect, incidental, special or consequential losses incurred by you as a result of using this service, including but not limited to mining revenue loss, equipment damage, etc.", "title10": "10、 Termination of Service", "clauseTermination1": "We have the right to terminate your service in the following circumstances: violation of these terms, laws and regulations, or damage to the interests of our company or other users.", "clauseTermination2": "After the termination of the service, your relevant data may be deleted or retained, and the specific processing method will be implemented in accordance with laws, regulations, and company policies.", "title11": "11、 Application of Law and Dispute Resolution", "clauseLaw1": "1. This clause is governed by the laws of Singapore.", "clauseLaw2": "2. In the event of a dispute, both parties shall resolve it through friendly consultation; If the negotiation fails, a lawsuit may be filed with a court with jurisdiction." } diff --git a/mining-pool/src/main.js b/mining-pool/src/main.js index d79dae9..7cbe1f2 100644 --- a/mining-pool/src/main.js +++ b/mining-pool/src/main.js @@ -15,6 +15,9 @@ import networkRecoveryMixin from './mixins/networkRecoveryMixin'; import './utils/loadingRecovery'; import errorNotificationManager from '../src/utils/errorNotificationManager'; +// 创建事件总线 用于组件通信 +Vue.prototype.$bus = new Vue(); + Vue.use(MetaInfo) Vue.prototype.$addStorageEvent = $addStorageEvent // 添加storage事件 Vue.config.productionTip = false @@ -23,7 +26,7 @@ Vue.use(ElementUI, { }); Vue.prototype.$axios = axios -// console.log = ()=>{} //全局关闭打印 +console.log = ()=>{} //全局关闭打印 // 全局注册混入 Vue.mixin(loadingStateMixin); Vue.mixin(networkRecoveryMixin); diff --git a/mining-pool/src/router/index.js b/mining-pool/src/router/index.js index 0197610..0664025 100644 --- a/mining-pool/src/router/index.js +++ b/mining-pool/src/router/index.js @@ -32,7 +32,7 @@ const childrenRoutes = [ component: () => import('../views/miningAccount/index.vue'), meta: {title: '挖矿账户页面', description:i18n.t(`seo.miningAccount`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool mining account, crypto mining stats, mining rewards, hashrate monitor, 矿池账户, 挖矿收益, 算力监控' keywords:{ en: 'M2Pool mining account, crypto mining stats, mining rewards, hashrate monitor, 矿池账户, 挖矿收益, 算力监控', @@ -63,7 +63,7 @@ const childrenRoutes = [ component: () => import('../views/reportBlock/index.vue'), meta: {title: '报块页面', description:i18n.t(`seo.reportBlock`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool 矿池,报块页面,幸运值,区块高度,Block page,Lucky Value,block height,Mining Pool' keywords:{ en: 'Block page,Lucky Value,block height,Mining Pool', @@ -308,7 +308,7 @@ const childrenRoutes = [ component: () => import('../views/submitWorkOrder/index.vue'), meta: {title: '提交工单页面', description:i18n.t(`seo.submitWorkOrder`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool 矿池,提交工单,技术支持,问题处理,Mining Pool,Work Order Submission, Technical Support, Troubleshooting' keywords:{ en: 'Mining Pool,Work Order Submission, Technical Support, Troubleshooting', @@ -322,7 +322,7 @@ const childrenRoutes = [ component: () => import('../views/workOrderRecords/index.vue'), meta: {title: '工单记录页面(用户)', description:i18n.t(`seo.workOrderRecords`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool 矿池,用户工单记录,处理状态,问题进度,User Work Order Records, Processing Status, Issue Progress' keywords:{ en: 'User Work Order Records, Processing Status, Issue Progress', @@ -336,7 +336,7 @@ const childrenRoutes = [ component: () => import('../views/userWorkDetails/index.vue'), meta: {title: '工单详情页面(用户)', description:i18n.t(`seo.userWorkDetails`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool 矿池,用户工单详情,问题描述,补充提交,User Work Order Details, Problem Description, Additional Submissions' keywords:{ en: 'User Work Order Details, Problem Description, Additional Submissions', @@ -408,7 +408,7 @@ const childrenRoutes = [ component: () => import('../views/personalCenter/index.vue'), meta: {title: '个人中心页面', description:i18n.t(`seo.personalCenter`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool 矿池,个人中心,挖矿账户,只读页面设置,安全设置,API密钥生成,Personal Center,Mining Account,Read-Only Page Setup,Security Settings,API Key Generation' keywords:{ en: 'Personal Center,Mining Account,Read-Only Page Setup,Security Settings,API Key Generation', @@ -422,7 +422,7 @@ const childrenRoutes = [ component: () => import('../views/personalCenter/personalMining/index.vue'), meta: {title: '挖矿账户设置页面', description:i18n.t(`seo.personalMining`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool 矿池,个人中心,挖矿账户设置,币种账户,Personal Center,Mining Account Settings,Coin Accounts' keywords:{ en: 'Personal Center,Mining Account Settings,Coin Accounts', @@ -436,7 +436,7 @@ const childrenRoutes = [ component: () => import('../views/personalCenter/readOnly/index.vue'), meta: {title: '只读页面设置', description:i18n.t(`seo.readOnly`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool 矿池,个人中心,只读页面设置,矿池分享,Personal Center,Read-Only Page Setting,Mining Pool Sharing' keywords:{ en: 'Personal Center,Read-Only Page Setting,Mining Pool Sharing', @@ -450,7 +450,7 @@ const childrenRoutes = [ component: () => import('../views/personalCenter/securitySetting/index.vue'), meta: {title: '安全设置页面', description:i18n.t(`seo.securitySetting`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool 矿池,安全设置,密码修改,Security settings, password change' keywords:{ en: 'Security settings, password change', @@ -464,7 +464,7 @@ const childrenRoutes = [ component: () => import('../views/personalCenter/personal/index.vue'), meta: {title: '个人信息页面', description:i18n.t(`seo.personal`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool 矿池,个人信息,登录历史,Personal Information, Login History' keywords:{ en: 'Personal Information, Login History', @@ -478,7 +478,7 @@ const childrenRoutes = [ component: () => import('../views/personalCenter/miningReport/index.vue'), meta: {title: '挖矿报告页面', description:i18n.t(`seo.miningReport`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool 矿池,个人中心,挖矿报告,订阅服务,Mining Report, Subscription Service' keywords:{ en: 'Mining Report, Subscription Service', @@ -493,7 +493,7 @@ const childrenRoutes = [ component: () => import('../views/personalCenter/personalAPI/index.vue'), meta: {title: 'API页面', description:i18n.t(`seo.personalAPI`), - allAuthority:[`admin`,`registered`], + allAuthority:[`admin`,`registered`,`customer_service`], // keywords: 'M2Pool 矿池,个人中心,API 页面,API密钥生成,API Page,API Key Generation' keywords:{ en: 'API Page,API Key Generation', @@ -657,6 +657,7 @@ router.beforeEach((to, from, next) => { let data = localStorage.getItem("jurisdiction"); let jurisdiction =JSON.parse(data); +console.log(jurisdiction,"权限"); localStorage.setItem('superReportError',"") let element = document.getElementsByClassName('el-main')[0]; diff --git a/mining-pool/src/store/index.js b/mining-pool/src/store/index.js index ceffa8e..cf260b8 100644 --- a/mining-pool/src/store/index.js +++ b/mining-pool/src/store/index.js @@ -5,12 +5,48 @@ Vue.use(Vuex) export default new Vuex.Store({ state: { + isLoggedIn: false, + userInfo: null }, getters: { + isLoggedIn: state => state.isLoggedIn, + userInfo: state => state.userInfo }, mutations: { + SET_LOGIN_STATE(state, isLoggedIn) { + state.isLoggedIn = isLoggedIn + }, + SET_USER_INFO(state, userInfo) { + state.userInfo = userInfo + }, + CLEAR_USER_DATA(state) { + state.isLoggedIn = false + state.userInfo = null + } }, actions: { + // 退出登录 + async logout({ commit }) { + try { + // 清除本地存储 + localStorage.removeItem('token') + localStorage.removeItem('userEmail') + localStorage.removeItem('jurisdiction') + + // 清除 Vuex 状态 + commit('CLEAR_USER_DATA') + + // 触发全局事件,通知其他组件用户已退出 + if (Vue.prototype.$bus) { + Vue.prototype.$bus.$emit('user-logged-out') + } + + return true + } catch (error) { + console.error('退出登录失败:', error) + return false + } + } }, modules: { } diff --git a/mining-pool/src/utils/request.js b/mining-pool/src/utils/request.js index 8a4cc8a..4568da6 100644 --- a/mining-pool/src/utils/request.js +++ b/mining-pool/src/utils/request.js @@ -4,6 +4,13 @@ import { Notification, MessageBox, Message } from 'element-ui' import loadingManager from './loadingManager'; import errorNotificationManager from './errorNotificationManager'; + +const pendingRequestMap = new Map(); //处理Request aborted 错误 + +function getRequestKey(config) { //处理Request aborted 错误 生成唯一 key 的函数 + const { url, method, params, data } = config; + return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&'); +} // 创建axios实例 const service = axios.create({ // axios中请求配置有baseURL选项,表示请求URL公共部分 @@ -143,9 +150,6 @@ window.addEventListener('online', () => { }); }); - - - // 使用错误提示管理器控制网络断开提示 window.addEventListener('offline', () => { if (window.vm && window.vm.$message && errorNotificationManager.canShowError('networkOffline')) { @@ -215,6 +219,22 @@ service.interceptors.request.use(config => { config.params = {}; config.url = url; } + + // 生成请求唯一key 处理Request aborted 错误 + const requestKey = getRequestKey(config); + + // 如果有相同请求,先取消 处理Request aborted 错误 + if (pendingRequestMap.has(requestKey)) { + const cancel = pendingRequestMap.get(requestKey); + cancel(); // 取消上一次请求 + pendingRequestMap.delete(requestKey); + } + + // 创建新的CancelToken 处理Request aborted 错误 + config.cancelToken = new axios.CancelToken(cancel => { + pendingRequestMap.set(requestKey, cancel); + }); + return config }, error => { Promise.reject(error) @@ -222,6 +242,10 @@ service.interceptors.request.use(config => { // 响应拦截器 service.interceptors.response.use(res => { + + // 请求完成后移除 + const requestKey = getRequestKey(res.config); + pendingRequestMap.delete(requestKey); // 未设置状态码则默认成功状态 const code = res.data.code || 200; // 获取错误信息 @@ -284,8 +308,15 @@ service.interceptors.response.use(res => { }, error => { - - + if (error.message && error.message.includes('canceled') || error.message.includes('Request aborted')) { + // 主动取消的请求,直接忽略,不提示 + return Promise.reject(error); + } + // 请求异常也要移除 处理Request aborted 错误 + if (error.config) { + const requestKey = getRequestKey(error.config); + pendingRequestMap.delete(requestKey); + } let { message } = error; diff --git a/mining-pool/src/views/ServiceTerms/index.vue b/mining-pool/src/views/ServiceTerms/index.vue index af5fa51..909d698 100644 --- a/mining-pool/src/views/ServiceTerms/index.vue +++ b/mining-pool/src/views/ServiceTerms/index.vue @@ -18,7 +18,8 @@

{{ $t(`ServiceTerms.clauseService1`) }}

{{ $t(`ServiceTerms.clauseService2`) }}

-

{{ $t(`ServiceTerms.clauseService3`) }} {{ $t(`ServiceTerms.clauseService4`) }}

+ +

{{ $t(`ServiceTerms.clauseService3`) }} {{ $t(`ServiceTerms.clauseService4`) }}

@@ -88,13 +89,13 @@

{{ $t(`ServiceTerms.clauseTermination2`) }}

-
+
@@ -117,7 +118,8 @@

{{ $t(`ServiceTerms.clauseService1`) }}

{{ $t(`ServiceTerms.clauseService2`) }}

-

{{ $t(`ServiceTerms.clauseService3`) }} {{ $t(`ServiceTerms.clauseService4`) }}

+ +

{{ $t(`ServiceTerms.clauseService3`) }} {{ $t(`ServiceTerms.clauseService4`) }}

@@ -187,13 +189,13 @@

{{ $t(`ServiceTerms.clauseTermination2`) }}

-
+
diff --git a/mining-pool/src/views/customerService/index.vue b/mining-pool/src/views/customerService/index.vue index 73424f6..08c120b 100644 --- a/mining-pool/src/views/customerService/index.vue +++ b/mining-pool/src/views/customerService/index.vue @@ -1,15 +1,44 @@ + - + @@ -340,29 +340,6 @@
-
- -
-
-
-
- coin - - {{ item.label }} - -
-
-
-
- -
-
- +
+

{{ $t(`home.describeTitle`) }}{{ $t(`home.describe`) }} {{ $t(`home.view`) }}

@@ -702,6 +680,7 @@ :key="item.value" :label="item.label" :value="item.value" + v-show="item.value !== 'enx'" >
@@ -783,7 +762,7 @@ export default { }; -