Compare commits
6 Commits
release
...
a3c6bf8e07
| Author | SHA1 | Date | |
|---|---|---|---|
| a3c6bf8e07 | |||
| 21a331680e | |||
| 3ee77547ff | |||
| 4332df54e8 | |||
| 368d0a8a10 | |||
| 4d436c725e |
278
README.md
278
README.md
@@ -1,278 +0,0 @@
|
||||
const { defineConfig } = require('@vue/cli-service');
|
||||
const path = require('path');
|
||||
const PrerenderSPAPlugin = require('@dreysolano/prerender-spa-plugin');
|
||||
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
|
||||
const SitemapWebpackPlugin = require('sitemap-webpack-plugin').default;
|
||||
const CompressionPlugin = require('compression-webpack-plugin');
|
||||
|
||||
module.exports = defineConfig({
|
||||
transpileDependencies: true,
|
||||
|
||||
devServer: {
|
||||
hot: true, // 启用HMR
|
||||
liveReload: true, // 启用实时重载
|
||||
client: {
|
||||
overlay: false // 禁用错误遮罩层
|
||||
}
|
||||
},
|
||||
|
||||
configureWebpack: config => {
|
||||
const baseConfig = {
|
||||
cache: {
|
||||
type: 'filesystem', // 使用文件系统缓存 加快二次构建速度 减少重复编译
|
||||
buildDependencies: {
|
||||
config: [__filename]
|
||||
},
|
||||
// 添加缓存配置
|
||||
cacheDirectory: path.resolve(__dirname, 'node_modules/.cache/webpack'),
|
||||
name: process.env.NODE_ENV // 区分环境
|
||||
},
|
||||
optimization: {
|
||||
moduleIds: 'deterministic',
|
||||
splitChunks: { // 代码分割配置文件系统缓存比内存缓存更持久 可以在多次构建之间复用编译结果
|
||||
chunks: 'all',
|
||||
minSize: 30000, // 最小分块大小
|
||||
maxSize: 300000, // 最大分块大小 避免单个文件过大
|
||||
cacheGroups: { // 缓存组配置
|
||||
vendors: { // 第三方库分组
|
||||
name: 'chunk-vendors',
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
priority: -10,
|
||||
chunks: 'initial'
|
||||
},
|
||||
common: { // 公共模块分组
|
||||
name: 'chunk-common',
|
||||
minChunks: 2,
|
||||
priority: -20,
|
||||
chunks: 'initial',
|
||||
reuseExistingChunk: true
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
plugins: [ //压缩静态资源 减少传输体积 提升加载速度
|
||||
new CompressionPlugin({
|
||||
test: /\.(js|css|html|svg)$/,
|
||||
threshold: 10240,
|
||||
minRatio: 0.8
|
||||
})
|
||||
]
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
// 优化预渲染插件配置
|
||||
const prerenderPlugin = new PrerenderSPAPlugin({
|
||||
staticDir: path.join(__dirname, 'dist'),
|
||||
// 只预渲染最重要的路由
|
||||
routes: ['/zh', '/en','/en/dataDisplay', '/zh/dataDisplay','/zh/rate', '/en/rate','/zh/ServiceTerms', '/en/ServiceTerms','/zh/apiFile', '/en/apiFile'],
|
||||
renderer: new Renderer({
|
||||
renderAfterTime: 1000, // 增加等待时间,确保内容加载完成
|
||||
maxConcurrentRoutes:2, // 降低并发数,避免资源竞争
|
||||
timeout: 10000, // 增加超时时间
|
||||
headless: true,
|
||||
|
||||
|
||||
|
||||
|
||||
}),
|
||||
|
||||
});
|
||||
|
||||
|
||||
const zhSitemapPlugin = new SitemapWebpackPlugin({
|
||||
base: 'https://m2pool.com/zh',
|
||||
paths: [
|
||||
{
|
||||
path: '/zh',
|
||||
changefreq: 'daily',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/zh/dataDisplay',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/zh/ServiceTerms',
|
||||
changefreq: 'monthly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/zh/apiFile',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/zh/rate',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/zh/AccessMiningPool/nexaAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/zh/AccessMiningPool/grsAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/zh/AccessMiningPool/monaAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/zh/AccessMiningPool/dgbsAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/zh/AccessMiningPool/dgbqAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/zh/AccessMiningPool/dgboAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/zh/AccessMiningPool/rxdAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
],
|
||||
options: {
|
||||
filename: 'sitemap-zh.xml',
|
||||
lastmod: true,
|
||||
changefreq: 'weekly',
|
||||
priority: 0.7
|
||||
}
|
||||
});
|
||||
|
||||
const enSitemapPlugin = new SitemapWebpackPlugin({
|
||||
base: 'https://m2pool.com/en',
|
||||
paths: [
|
||||
{
|
||||
path: '/en',
|
||||
priority: 1.0,
|
||||
changefreq: 'daily',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/en/dataDisplay',
|
||||
priority: 0.8,
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/en/ServiceTerms',
|
||||
priority: 0.6,
|
||||
changefreq: 'monthly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/en/apiFile',
|
||||
priority: 0.7,
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/en/rate',
|
||||
priority: 0.8,
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/en/AccessMiningPool/nexaAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/en/AccessMiningPool/grsAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/en/AccessMiningPool/monaAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/en/AccessMiningPool/dgbsAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/en/AccessMiningPool/dgbqAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/en/AccessMiningPool/dgboAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
path: '/en/AccessMiningPool/rxdAccess',
|
||||
changefreq: 'weekly',
|
||||
lastmod: new Date().toISOString()
|
||||
},
|
||||
|
||||
],
|
||||
options: {
|
||||
filename: 'sitemap-en.xml',
|
||||
lastmod: true,
|
||||
changefreq: 'weekly',
|
||||
priority: 0.7
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
baseConfig.plugins.push(zhSitemapPlugin);
|
||||
baseConfig.plugins.push(enSitemapPlugin);
|
||||
baseConfig.plugins.push(prerenderPlugin);
|
||||
|
||||
}
|
||||
|
||||
return baseConfig;
|
||||
},
|
||||
|
||||
chainWebpack: config => {
|
||||
// HTML压缩配置
|
||||
config.plugin('html').tap(args => {
|
||||
args[0].minify = {
|
||||
removeComments: true, // 删除 HTML 注释减小文件体积
|
||||
collapseWhitespace: true, // 压缩空白字符 删除多余的空格和换行
|
||||
removeAttributeQuotes: true, // 删除属性的引号
|
||||
collapseBooleanAttributes: true, // 简化布尔属性
|
||||
removeScriptTypeAttributes: true // 删除默认的 script type 属性type="text/javascript"
|
||||
};
|
||||
// META 标签配置
|
||||
args[0].meta = {
|
||||
// 移动端视口配置
|
||||
viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no',
|
||||
'format-detection': 'telephone=no',// 禁用电话号码自动识别
|
||||
'apple-mobile-web-app-capable': 'yes' // 支持添加到 iOS 主屏幕
|
||||
};
|
||||
return args;
|
||||
});
|
||||
|
||||
// 移除 prefetch 插件
|
||||
//禁用 Vue CLI 默认的预取功能 prefetch 会在主资源加载完后,
|
||||
// 自动下载所有其他路由的资源对于大型应用,可能会预加载过多不必要的资源
|
||||
config.plugins.delete('prefetch')
|
||||
},
|
||||
//生产环境不生成 source map 文件源码映射信息 减小打包体积 提高网站安全性
|
||||
productionSourceMap: false,
|
||||
|
||||
css: {
|
||||
extract: true, //组件中的 CSS 提取至独立的 CSS 文件中 支持并行加载,减少页面阻塞
|
||||
sourceMap: false,// CSS 不启用 source maps 减少构建文件大小
|
||||
loaderOptions: {
|
||||
css: {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Binary file not shown.
@@ -1,16 +1,19 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view class="page" />
|
||||
|
||||
<!-- <ChatWidget /> -->
|
||||
</div>
|
||||
</template>
|
||||
<script >
|
||||
import ChatWidget from '../src/components/ChatWidget.vue';
|
||||
import { Debounce, throttle } from '@/utils/publicMethods';
|
||||
import Vue from 'vue'
|
||||
export default {
|
||||
name: 'App',
|
||||
|
||||
|
||||
components: {
|
||||
ChatWidget
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
|
||||
68
mining-pool/src/api/customerService.js
Normal file
68
mining-pool/src/api/customerService.js
Normal file
@@ -0,0 +1,68 @@
|
||||
import request from '../utils/request'
|
||||
|
||||
//历史聊天记录查询 用户查询七天前的聊天信息
|
||||
export function getHistory() {
|
||||
return request({
|
||||
url: `chat/message/find/history/message`,
|
||||
method: 'get',
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
//历史聊天记录查询 查询七天内记录
|
||||
export function getHistory7() {
|
||||
return request({
|
||||
url: `chat/message/find/recently/message`,
|
||||
method: 'get',
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
//用户点击对话框默认已读
|
||||
export function getReadMessage(data) {
|
||||
return request({
|
||||
url: `chat/message/read/message`,
|
||||
method: 'post',
|
||||
data
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
//聊天列表
|
||||
export function getRoomList() {
|
||||
return request({
|
||||
url: `/chat/rooms/find/room/list`,
|
||||
method: 'get',
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//重要聊天标记
|
||||
export function getUpdateRoom(data) {
|
||||
return request({
|
||||
url: `/chat/rooms/update/room`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
//图片上传接口
|
||||
export function getFileUpdate(data) {
|
||||
return request({
|
||||
url: `file/update`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
//图根据当前用户邮箱查询聊天室id
|
||||
export function getUserid() {
|
||||
return request({
|
||||
url: `chat/rooms/find/room/by/userid`,
|
||||
method: 'get',
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
893
mining-pool/src/components/ChatWidget.vue
Normal file
893
mining-pool/src/components/ChatWidget.vue
Normal file
@@ -0,0 +1,893 @@
|
||||
<template>
|
||||
<div class="chat-widget">
|
||||
<!-- 聊天图标 -->
|
||||
<div
|
||||
class="chat-icon"
|
||||
@click="toggleChat"
|
||||
:class="{ active: isChatOpen }"
|
||||
aria-label="打开客服聊天"
|
||||
tabindex="0"
|
||||
@keydown.enter="toggleChat"
|
||||
@keydown.space="toggleChat"
|
||||
>
|
||||
<i class="el-icon-chat-dot-round"></i>
|
||||
<span v-if="unreadMessages > 0" class="unread-badge">{{
|
||||
unreadMessages
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
<!-- 聊天对话框 -->
|
||||
<transition name="chat-slide">
|
||||
<div v-show="isChatOpen" class="chat-dialog">
|
||||
<div class="chat-header">
|
||||
<div class="chat-title">{{ $t("chat.title") || "在线客服" }}</div>
|
||||
<div class="chat-actions">
|
||||
<i class="el-icon-minus" @click="minimizeChat"></i>
|
||||
<i class="el-icon-close" @click="closeChat"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-body" ref="chatBody">
|
||||
<!-- 连接状态提示 -->
|
||||
<div v-if="connectionStatus === 'connecting'" class="chat-status connecting">
|
||||
<i class="el-icon-loading"></i>
|
||||
<p>正在连接客服系统...</p>
|
||||
</div>
|
||||
<div v-else-if="connectionStatus === 'error'" class="chat-status error">
|
||||
<i class="el-icon-warning"></i>
|
||||
<p>连接失败,请稍后重试</p>
|
||||
<button @click="connectWebSocket" class="retry-button">重试连接</button>
|
||||
</div>
|
||||
|
||||
<!-- 消息列表 -->
|
||||
<template v-else>
|
||||
<div v-if="messages.length === 0" class="chat-empty">
|
||||
{{ $t("chat.welcome") || "欢迎使用在线客服,请问有什么可以帮您?" }}
|
||||
</div>
|
||||
<div
|
||||
v-for="(msg, index) in messages"
|
||||
:key="index"
|
||||
class="chat-message"
|
||||
:class="{
|
||||
'chat-message-user': msg.type === 'user',
|
||||
'chat-message-system': msg.type === 'system',
|
||||
}"
|
||||
>
|
||||
<div class="message-avatar">
|
||||
<i v-if="msg.type === 'system'" class="el-icon-service"></i>
|
||||
<i v-else class="el-icon-user"></i>
|
||||
</div>
|
||||
<div class="message-content">
|
||||
<!-- 文本消息 -->
|
||||
<div v-if="!msg.isImage" class="message-text">{{ msg.text }}</div>
|
||||
|
||||
<!-- 图片消息 -->
|
||||
<div v-else class="message-image">
|
||||
<img :src="msg.imageUrl" @click="previewImage(msg.imageUrl)" alt="聊天图片" />
|
||||
</div>
|
||||
|
||||
<div class="message-time">{{ formatTime(msg.time) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="chat-footer">
|
||||
<div class="chat-toolbar">
|
||||
<label for="imageUpload" class="image-upload-label" :class="{ 'disabled': connectionStatus !== 'connected' }">
|
||||
<i class="el-icon-picture-outline"></i>
|
||||
</label>
|
||||
<input
|
||||
type="file"
|
||||
id="imageUpload"
|
||||
ref="imageUpload"
|
||||
accept="image/*"
|
||||
@change="handleImageUpload"
|
||||
style="display: none;"
|
||||
:disabled="connectionStatus !== 'connected'"
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
class="chat-input"
|
||||
v-model="inputMessage"
|
||||
@keyup.enter="sendMessage"
|
||||
:placeholder="$t('chat.inputPlaceholder') || '请输入您的问题...'"
|
||||
:disabled="connectionStatus !== 'connected'"
|
||||
/>
|
||||
<button
|
||||
class="chat-send"
|
||||
@click="sendMessage"
|
||||
:disabled="connectionStatus !== 'connected' || !inputMessage.trim()"
|
||||
>
|
||||
{{ $t("chat.send") || "发送" }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 图片预览 -->
|
||||
<div v-if="showImagePreview" class="image-preview-overlay" @click="closeImagePreview">
|
||||
<div class="image-preview-container">
|
||||
<img :src="previewImageUrl" class="preview-image" />
|
||||
<i class="el-icon-close preview-close" @click="closeImagePreview"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Client } from '@stomp/stompjs';
|
||||
import { getUserid } from '../api/customerService';
|
||||
export default {
|
||||
name: "ChatWidget",
|
||||
data() {
|
||||
return {
|
||||
isChatOpen: false,
|
||||
inputMessage: "",
|
||||
messages: [],
|
||||
unreadMessages: 0,
|
||||
// 图片预览相关
|
||||
showImagePreview: false,
|
||||
previewImageUrl: '',
|
||||
// WebSocket 相关
|
||||
stompClient: null,
|
||||
connectionStatus: 'disconnected', // disconnected, connecting, connected, error
|
||||
userType: 0, // 0 游客 1 登录用户 2 客服
|
||||
userEmail: '', // 用户标识
|
||||
// 自动回复配置
|
||||
autoResponses: {
|
||||
hello: "您好,有什么可以帮助您的?",
|
||||
你好: "您好,有什么可以帮助您的?",
|
||||
hi: "您好,有什么可以帮助您的?",
|
||||
挖矿: "您可以查看我们的挖矿教程,或者直接创建矿工账户开始挖矿。",
|
||||
算力: "您可以在首页查看当前的矿池算力和您的个人算力。",
|
||||
收益: "收益根据您的算力贡献按比例分配,详情可以查看收益计算器。",
|
||||
帮助: "您可以查看我们的帮助文档,或者提交工单咨询具体问题。",
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener("click", this.handleClickOutside);
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
async fetchUserid(){
|
||||
const res = await getUserid();
|
||||
if(res &&res.code == 200){
|
||||
this.roomId = res.data;
|
||||
console.log(res,"及附加覅");
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// 初始化 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';
|
||||
}
|
||||
},
|
||||
|
||||
// 接收消息处理
|
||||
onMessageReceived(message) {
|
||||
console.log('收到消息:', message.body);
|
||||
try {
|
||||
const data = JSON.parse(message.body);
|
||||
|
||||
// 添加客服消息
|
||||
this.messages.push({
|
||||
type: 'system',
|
||||
text: data.content,
|
||||
isImage: data.type === 'image',
|
||||
imageUrl: data.type === 'image' ? data.content : null,
|
||||
time: new Date(),
|
||||
});
|
||||
|
||||
// 如果聊天窗口没有打开,显示未读消息数
|
||||
if (!this.isChatOpen) {
|
||||
this.unreadMessages++;
|
||||
}
|
||||
|
||||
// 滚动到底部
|
||||
this.$nextTick(() => {
|
||||
this.scrollToBottom();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('解析消息失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 切换聊天窗口
|
||||
toggleChat() {
|
||||
this.isChatOpen = !this.isChatOpen;
|
||||
|
||||
if (this.isChatOpen) {
|
||||
this.unreadMessages = 0;
|
||||
|
||||
// 如果未连接,则连接 WebSocket
|
||||
if (this.connectionStatus === 'disconnected') {
|
||||
this.initWebSocket();
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.scrollToBottom();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
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:0,// 0 文本 1图片
|
||||
text: messageText,
|
||||
isImage: false,
|
||||
time: new Date(),
|
||||
email:"",// 接收者邮箱?
|
||||
receiveUserType:2,// 接受用户类型0 游客 1 登录用户 2 客服人员
|
||||
sendUserType:this.userType,// 发送者类型0 游客 1 登录用户 2 客服人员
|
||||
roomId:this.roomId,// 聊天室ID
|
||||
});
|
||||
|
||||
// 通过 WebSocket 发送消息
|
||||
if (this.stompClient && this.stompClient.connected) {
|
||||
this.stompClient.publish({
|
||||
destination: '/send/message',
|
||||
body: JSON.stringify({
|
||||
content: messageText,
|
||||
type: 'text'
|
||||
})
|
||||
});
|
||||
} 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);
|
||||
},
|
||||
|
||||
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');
|
||||
this.fetchUserid();
|
||||
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:1,// 0 文本 1图片
|
||||
text: "",
|
||||
isImage: true,
|
||||
imageUrl: imageUrl,
|
||||
time: new Date(),
|
||||
email:"",// 接收者邮箱?
|
||||
receiveUserType:2,// 接受用户类型0 游客 1 登录用户 2 客服人员
|
||||
sendUserType:this.userType,// 发送者类型0 游客 1 登录用户 2 客服人员
|
||||
roomId:this.roomId,// 聊天室ID
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
// 通过 WebSocket 发送图片消息
|
||||
if (this.stompClient && this.stompClient.connected) {
|
||||
this.stompClient.publish({
|
||||
destination: '/send/message',
|
||||
body: JSON.stringify({
|
||||
content: imageUrl,
|
||||
type: 'image'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.chat-widget {
|
||||
position: fixed;
|
||||
bottom: 40px;
|
||||
right: 60px;
|
||||
z-index: 1000;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.chat-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
background-color: #AC85E0;
|
||||
color: white;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
|
||||
i {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
background-color: #6E3EDB;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #6E3EDB;
|
||||
}
|
||||
}
|
||||
|
||||
.unread-badge {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: -5px;
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chat-dialog {
|
||||
position: absolute;
|
||||
bottom: 80px;
|
||||
right: 0;
|
||||
width: 350px;
|
||||
height: 450px;
|
||||
background-color: white;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
background-color: #AC85E0;
|
||||
color: white;
|
||||
padding: 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chat-title {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.chat-actions {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-body {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 15px;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.chat-status {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
i {
|
||||
font-size: 32px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 8px 0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&.connecting i {
|
||||
color: #AC85E0;
|
||||
}
|
||||
|
||||
&.error {
|
||||
i {
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #e74c3c;
|
||||
}
|
||||
}
|
||||
|
||||
.retry-button {
|
||||
margin-top: 16px;
|
||||
padding: 8px 16px;
|
||||
background-color: #AC85E0;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #6E3EDB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-empty {
|
||||
color: #777;
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.chat-message {
|
||||
display: flex;
|
||||
margin-bottom: 15px;
|
||||
|
||||
&.chat-message-user {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.message-content {
|
||||
background-color: #AC85E0;
|
||||
color: white;
|
||||
border-radius: 18px 18px 0 18px;
|
||||
}
|
||||
|
||||
.message-time {
|
||||
text-align: right;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
&.chat-message-system {
|
||||
.message-content {
|
||||
background-color: white;
|
||||
border-radius: 18px 18px 18px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message-avatar {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #e0e0e0;
|
||||
margin: 0 10px;
|
||||
|
||||
i {
|
||||
font-size: 18px;
|
||||
color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.message-content {
|
||||
max-width: 70%;
|
||||
padding: 10px 15px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.message-text {
|
||||
line-height: 1.4;
|
||||
font-size: 14px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.message-image {
|
||||
img {
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.03);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message-time {
|
||||
font-size: 11px;
|
||||
color: #999;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.chat-footer {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chat-toolbar {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.image-upload-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
color: #666;
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
color: #AC85E0;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
flex: 1;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 20px;
|
||||
padding: 8px 15px;
|
||||
outline: none;
|
||||
|
||||
&:focus:not(:disabled) {
|
||||
border-color: #AC85E0;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: #f5f5f5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-send {
|
||||
background-color: #AC85E0;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
padding: 8px 15px;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
background-color: #6E3EDB;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
// 图片预览
|
||||
.image-preview-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
z-index: 1100;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.image-preview-container {
|
||||
position: relative;
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
max-width: 100%;
|
||||
max-height: 90vh;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.preview-close {
|
||||
position: absolute;
|
||||
top: -40px;
|
||||
right: 0;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
// 动画效果
|
||||
.chat-slide-enter-active, .chat-slide-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.chat-slide-enter, .chat-slide-leave-to {
|
||||
transform: translateY(20px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
// 移动端适配
|
||||
@media (max-width: 768px) {
|
||||
.chat-widget {
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.chat-dialog {
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
bottom: 70px;
|
||||
}
|
||||
|
||||
.message-image img {
|
||||
max-width: 150px;
|
||||
max-height: 150px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
32
mining-pool/src/i18n/ChatWidget.js
Normal file
32
mining-pool/src/i18n/ChatWidget.js
Normal file
@@ -0,0 +1,32 @@
|
||||
export const ChatWidget_zh = {
|
||||
chat:{
|
||||
|
||||
title: '在线客服',
|
||||
welcome: '欢迎使用在线客服,请问有什么可以帮您?',
|
||||
placeholder: '请输入您的消息...',
|
||||
send: '发送',
|
||||
close: '关闭',
|
||||
inputPlaceholder:"请输入您的问题...",
|
||||
onlyImages:"只能上传图片文件!",
|
||||
imageTooLarge:"图片大小不能超过5MB!",
|
||||
imageReceived:"已收到您的图片,我们会尽快处理您的问题。",
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
|
||||
export const ChatWidget_en = {
|
||||
|
||||
|
||||
chat:{
|
||||
title: 'Online Customer Service',
|
||||
welcome: 'Welcome to the online customer service, what can I help you with?',
|
||||
placeholder: 'Please enter your message...',
|
||||
send: 'Send',
|
||||
close: 'Close',
|
||||
inputPlaceholder:"Please enter your question...",
|
||||
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.",
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import {workOrder_zh,workOrder_en} from'./submitWorkOrder'
|
||||
import {alerts_zh,alerts_en} from'./alerts'
|
||||
import {seo_zh,seo_en} from'./seo'
|
||||
import {chooseUs_zh,chooseUs_en} from'./dataDisplay'
|
||||
import {ChatWidget_zh,ChatWidget_en} from'./ChatWidget'
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +31,7 @@ export default {
|
||||
...alerts_zh,
|
||||
...seo_zh,
|
||||
...chooseUs_zh,
|
||||
|
||||
...ChatWidget_zh,
|
||||
|
||||
|
||||
},
|
||||
@@ -50,7 +51,7 @@ export default {
|
||||
...alerts_en,
|
||||
...seo_en,
|
||||
...chooseUs_en,
|
||||
|
||||
...ChatWidget_en,
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@ import './assets/icons/iconfont/iconfont.css'
|
||||
import {$addStorageEvent} from '../src/utils/publicMethods'
|
||||
import MetaInfo from 'vue-meta-info'
|
||||
import loadingStateMixin from './utils/loadingStateMixin';
|
||||
import networkRecoveryMixin from './mixins/networkRecoveryMixin';
|
||||
import './utils/loadingRecovery';
|
||||
import errorNotificationManager from '../src/utils/errorNotificationManager';
|
||||
|
||||
Vue.use(MetaInfo)
|
||||
Vue.prototype.$addStorageEvent = $addStorageEvent // 添加storage事件
|
||||
@@ -21,7 +24,9 @@ Vue.use(ElementUI, {
|
||||
Vue.prototype.$axios = axios
|
||||
|
||||
console.log = ()=>{} //全局关闭打印
|
||||
// 全局注册混入
|
||||
Vue.mixin(loadingStateMixin);
|
||||
Vue.mixin(networkRecoveryMixin);
|
||||
|
||||
Vue.prototype.$baseApi = process.env.VUE_APP_BASE_URL //图片base路径
|
||||
const screenWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||
@@ -45,6 +50,11 @@ router.beforeEach((to, from, next) => {
|
||||
next();
|
||||
});
|
||||
|
||||
// 定期清理过期的错误记录
|
||||
setInterval(() => {
|
||||
errorNotificationManager.cleanup();
|
||||
}, 60000); // 每分钟清理一次
|
||||
|
||||
window.vm = new Vue({
|
||||
router,
|
||||
store,
|
||||
|
||||
61
mining-pool/src/mixins/networkRecoveryMixin.js
Normal file
61
mining-pool/src/mixins/networkRecoveryMixin.js
Normal file
@@ -0,0 +1,61 @@
|
||||
//处理断网重连后数据刷新的混入
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 注册需要在网络恢复时调用的方法名
|
||||
recoveryMethods: [],
|
||||
// 上次调用这些方法时的参数
|
||||
methodParams: {}
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 注册需要在网络恢复时自动重新调用的方法
|
||||
* @param {String} methodName - 方法名
|
||||
* @param {*} params - 调用方法时需要的参数
|
||||
*/
|
||||
registerRecoveryMethod(methodName, params) {
|
||||
if (typeof this[methodName] === 'function' && !this.recoveryMethods.includes(methodName)) {
|
||||
this.recoveryMethods.push(methodName);
|
||||
this.methodParams[methodName] = params;
|
||||
console.log(`[NetworkRecovery] 注册方法: ${methodName}`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 更新方法的参数
|
||||
* @param {String} methodName - 方法名
|
||||
* @param {*} params - 新的参数
|
||||
*/
|
||||
updateMethodParams(methodName, params) {
|
||||
if (this.recoveryMethods.includes(methodName)) {
|
||||
this.methodParams[methodName] = params;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 网络恢复后调用所有注册的方法
|
||||
*/
|
||||
handleNetworkRecovery() {
|
||||
console.log('[NetworkRecovery] 网络已恢复,正在刷新数据...');
|
||||
this.recoveryMethods.forEach(methodName => {
|
||||
if (typeof this[methodName] === 'function') {
|
||||
const params = this.methodParams[methodName];
|
||||
console.log(`[NetworkRecovery] 重新调用方法: ${methodName}`);
|
||||
this[methodName](params);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// 监听网络恢复事件
|
||||
window.addEventListener('network-retry-complete', this.handleNetworkRecovery);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
// 清理事件监听
|
||||
window.removeEventListener('network-retry-complete', this.handleNetworkRecovery);
|
||||
}
|
||||
};
|
||||
@@ -118,6 +118,22 @@ const childrenRoutes = [
|
||||
|
||||
}
|
||||
},
|
||||
{//在线客服
|
||||
path: 'customerService',
|
||||
name: 'CustomerService',
|
||||
component: () => import('../views/customerService/index.vue'),
|
||||
meta: {title: '在线客服',
|
||||
description:i18n.t(`seo.apiFile`),
|
||||
allAuthority:[`all`],
|
||||
// keywords: 'M2Pool 矿池,API 文档,认证 token,接口调用,API file,authentication token,Interface call'
|
||||
keywords:{
|
||||
en: 'API file,authentication token,Interface call',
|
||||
zh: 'M2Pool 矿池,API 文档,认证 token,接口调用'
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
{//接入矿池页面
|
||||
path: '/:lang/AccessMiningPool',
|
||||
name: 'AccessMiningPool',
|
||||
|
||||
74
mining-pool/src/utils/errorNotificationManager.js
Normal file
74
mining-pool/src/utils/errorNotificationManager.js
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* 错误提示管理器
|
||||
* 用于控制错误提示的频率,避免短时间内重复显示相同类型的错误
|
||||
*/
|
||||
class ErrorNotificationManager {
|
||||
constructor() {
|
||||
// 记录最近显示的错误信息
|
||||
this.recentErrors = new Map();
|
||||
// 默认节流时间 (30秒)
|
||||
this.throttleTime = 3000;
|
||||
// 错误类型映射
|
||||
this.errorTypes = {
|
||||
'Network Error': 'network',
|
||||
'timeout': 'timeout',
|
||||
'Request failed with status code': 'statusCode',
|
||||
// 添加网络状态类型
|
||||
'networkReconnected': 'networkStatus',
|
||||
'NetworkError': 'network'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误类型
|
||||
* @param {String} message 错误信息
|
||||
* @returns {String} 错误类型
|
||||
*/
|
||||
getErrorType(message) {
|
||||
for (const [key, type] of Object.entries(this.errorTypes)) {
|
||||
if (message.includes(key)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否可以显示错误
|
||||
* @param {String} message 错误信息
|
||||
* @returns {Boolean} 是否可以显示
|
||||
*/
|
||||
canShowError(message) {
|
||||
const errorType = this.getErrorType(message);
|
||||
const now = Date.now();
|
||||
|
||||
// 检查同类型的错误是否最近已经显示过
|
||||
if (this.recentErrors.has(errorType)) {
|
||||
const lastTime = this.recentErrors.get(errorType);
|
||||
if (now - lastTime < this.throttleTime) {
|
||||
console.log(`[错误提示] 已抑制重复错误: ${errorType}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新最后显示时间
|
||||
this.recentErrors.set(errorType, now);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期的错误记录
|
||||
*/
|
||||
cleanup() {
|
||||
const now = Date.now();
|
||||
this.recentErrors.forEach((time, type) => {
|
||||
if (now - time > this.throttleTime) {
|
||||
this.recentErrors.delete(type);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 创建单例实例
|
||||
const errorNotificationManager = new ErrorNotificationManager();
|
||||
export default errorNotificationManager;
|
||||
41
mining-pool/src/utils/loadingRecovery.js
Normal file
41
mining-pool/src/utils/loadingRecovery.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
/**
|
||||
* 自动恢复加载状态的指令
|
||||
* 用法: v-loading-recovery="{ loading: 'loadingProp', recovery: ['method1', 'method2'] }"
|
||||
*/
|
||||
export const loadingRecoveryDirective = {
|
||||
// 当绑定元素插入到 DOM 中时
|
||||
inserted(el, binding, vnode) {
|
||||
const component = vnode.context;
|
||||
const { loading, recovery } = binding.value || {};
|
||||
|
||||
if (!loading || !recovery || !Array.isArray(recovery)) return;
|
||||
|
||||
// 为组件添加加载状态恢复的逻辑
|
||||
const handleNetworkRecovery = () => {
|
||||
// 当网络恢复时,自动设置loading为false
|
||||
if (component[loading]) {
|
||||
component[loading] = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 保存到元素上,以便后续清理
|
||||
el._loadingRecovery = handleNetworkRecovery;
|
||||
window.addEventListener('network-retry-complete', handleNetworkRecovery);
|
||||
|
||||
console.log(`[LoadingRecovery] 添加加载状态恢复: ${loading}`);
|
||||
},
|
||||
|
||||
// 当指令与元素解绑时
|
||||
unbind(el) {
|
||||
// 清理事件监听
|
||||
if (el._loadingRecovery) {
|
||||
window.removeEventListener('network-retry-complete', el._loadingRecovery);
|
||||
delete el._loadingRecovery;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 注册全局指令
|
||||
Vue.directive('loading-recovery', loadingRecoveryDirective);
|
||||
@@ -2,6 +2,8 @@ import axios from 'axios'
|
||||
import errorCode from './errorCode'
|
||||
import { Notification, MessageBox, Message } from 'element-ui'
|
||||
import loadingManager from './loadingManager';
|
||||
import errorNotificationManager from './errorNotificationManager';
|
||||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
@@ -19,10 +21,51 @@ let lastNetworkErrorTime = 0; // 上次网络错误提示时间
|
||||
let pendingRequests = new Map();
|
||||
|
||||
|
||||
// 网络状态监听器
|
||||
// 网络状态最后提示时间
|
||||
let lastNetworkStatusTime = {
|
||||
online: 0,
|
||||
offline: 0
|
||||
};
|
||||
|
||||
// 创建一个全局标志,确保每次网络恢复只显示一次提示
|
||||
let networkRecoveryInProgress = false;
|
||||
|
||||
// 网络状态监听器
|
||||
window.addEventListener('online', () => {
|
||||
// 网络恢复时,重试所有待处理的请求
|
||||
const now = Date.now();
|
||||
|
||||
// 避免短时间内多次触发
|
||||
if (networkRecoveryInProgress) {
|
||||
console.log('[网络] 网络恢复处理已在进行中,忽略重复事件');
|
||||
return;
|
||||
}
|
||||
|
||||
networkRecoveryInProgress = true;
|
||||
|
||||
// 严格检查是否应该显示提示
|
||||
if (now - lastNetworkStatusTime.online > 30000) { // 30秒内不重复提示
|
||||
lastNetworkStatusTime.online = now;
|
||||
|
||||
try {
|
||||
if (window.vm && window.vm.$message) {
|
||||
// 确保消息只显示一次
|
||||
window.vm.$message({
|
||||
message: window.vm.$i18n.t('home.networkReconnected') || '网络已重新连接,正在恢复数据...',
|
||||
type: 'success',
|
||||
duration: 5000,
|
||||
showClose: true,
|
||||
});
|
||||
console.log('[网络] 显示网络恢复提示, 时间:', new Date().toLocaleTimeString());
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[网络] 显示网络恢复提示失败:', e);
|
||||
}
|
||||
} else {
|
||||
console.log('[网络] 抑制重复的网络恢复提示, 间隔过短:', now - lastNetworkStatusTime.online + 'ms');
|
||||
}
|
||||
|
||||
// 网络恢复时,重试所有待处理的请求
|
||||
const pendingPromises = [];
|
||||
|
||||
pendingRequests.forEach(async (request, key) => {
|
||||
@@ -71,34 +114,56 @@ window.addEventListener('online', () => {
|
||||
// 等待所有请求完成
|
||||
Promise.allSettled(pendingPromises).then(() => {
|
||||
// 重置所有 loading 状态
|
||||
loadingManager.resetAllLoadingStates();
|
||||
if (loadingManager) {
|
||||
loadingManager.resetAllLoadingStates();
|
||||
}
|
||||
|
||||
// 手动重置一些关键的 loading 状态
|
||||
if (window.vm) {
|
||||
// 常见的加载状态
|
||||
const commonLoadingProps = [
|
||||
'minerChartLoading', 'reportBlockLoading', 'apiPageLoading',
|
||||
'MiningLoading', 'miniLoading'
|
||||
];
|
||||
|
||||
commonLoadingProps.forEach(prop => {
|
||||
if (typeof window.vm[prop] !== 'undefined') {
|
||||
window.vm[prop] = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 触发网络重试完成事件
|
||||
window.dispatchEvent(new CustomEvent('network-retry-complete'));
|
||||
});
|
||||
|
||||
// 显示网络恢复提示
|
||||
if (window.vm && window.vm.$message) {
|
||||
window.vm.$message({
|
||||
message: window.vm.$i18n.t('home.networkReconnected') || '网络已重新连接,正在恢复数据...',
|
||||
type: 'success',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
// 重置网络恢复标志
|
||||
setTimeout(() => {
|
||||
networkRecoveryInProgress = false;
|
||||
}, 5000); // 5秒后允许再次处理网络恢复
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// 使用错误提示管理器控制网络断开提示
|
||||
window.addEventListener('offline', () => {
|
||||
if (window.vm && window.vm.$message) {
|
||||
if (window.vm && window.vm.$message && errorNotificationManager.canShowError('networkOffline')) {
|
||||
window.vm.$message({
|
||||
message: window.vm.$i18n.t('home.networkOffline') || '网络连接已断开,系统将在恢复连接后自动重试',
|
||||
type: 'warning',
|
||||
duration: 3000
|
||||
type: 'error',
|
||||
duration: 5000,
|
||||
showClose: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
service.defaults.retry = 2;// 重试次数
|
||||
service.defaults.retryDelay = 2000;
|
||||
service.defaults.shouldRetry = (error) => true
|
||||
service.defaults.shouldRetry = (error) => {
|
||||
// 只有网络错误或超时错误才进行重试
|
||||
return error.message === "Network Error" || error.message.includes("timeout");
|
||||
};
|
||||
|
||||
localStorage.setItem('superReportError', "")
|
||||
let superReportError = localStorage.getItem('superReportError')
|
||||
@@ -224,7 +289,6 @@ service.interceptors.response.use(res => {
|
||||
|
||||
|
||||
let { message } = error;
|
||||
|
||||
if (message == "Network Error" || message.includes("timeout")) {
|
||||
if (!navigator.onLine) {
|
||||
// 断网状态,添加到重试队列
|
||||
@@ -262,30 +326,37 @@ service.interceptors.response.use(res => {
|
||||
|
||||
console.log('请求已加入断网重连队列:', error.config.url);
|
||||
}
|
||||
} else if ((error.config.retry > 0 && error.config)) {
|
||||
// 保留现有的重试逻辑
|
||||
error.config.retry--;
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve(service(error.config));
|
||||
}, 2000);
|
||||
});
|
||||
} else {
|
||||
// 网络已连接,但请求失败,尝试重试
|
||||
// 确保 config 中有 __retryCount 字段
|
||||
error.config.__retryCount = error.config.__retryCount || 0;
|
||||
|
||||
// 判断是否可以重试
|
||||
if (error.config.__retryCount < service.defaults.retry && service.defaults.shouldRetry(error)) {
|
||||
// 增加重试计数
|
||||
error.config.__retryCount += 1;
|
||||
|
||||
console.log(`[请求重试] ${error.config.url} - 第 ${error.config.__retryCount} 次重试`);
|
||||
|
||||
// 创建新的Promise等待一段时间后重试
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve(service(error.config));
|
||||
}, service.defaults.retryDelay);
|
||||
});
|
||||
}
|
||||
|
||||
// 达到最大重试次数,不再重试
|
||||
console.log(`[请求失败] ${error.config.url} - 已达到最大重试次数`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (!superReportError) {
|
||||
superReportError = "error"
|
||||
localStorage.setItem('superReportError', superReportError)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
// message = "后端接口网络连接异常,请刷新重试";
|
||||
const now = Date.now();
|
||||
if (now - lastNetworkErrorTime > NETWORK_ERROR_THROTTLE_TIME) {
|
||||
lastNetworkErrorTime = now; // 更新最后提示时间
|
||||
//使用错误提示管理器errorNotificationManager
|
||||
if (errorNotificationManager.canShowError(message)) {
|
||||
if (message == "Network Error") {
|
||||
Message({
|
||||
message: window.vm.$i18n.t(`home.NetworkError`),
|
||||
type: 'error',
|
||||
@@ -293,42 +364,38 @@ service.interceptors.response.use(res => {
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
// message = "系统接口请求超时,请刷新重试";
|
||||
Message({
|
||||
message: window.vm.$i18n.t(`home.requestTimeout`),
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
})
|
||||
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
// message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
Message({
|
||||
message: "系统接口" + message.substr(message.length - 3) + "异常",
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
})
|
||||
else if (message.includes("timeout")) {
|
||||
Message({
|
||||
message: window.vm.$i18n.t(`home.requestTimeout`),
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
Message({
|
||||
message: "系统接口" + message.substr(message.length - 3) + "异常",
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
});
|
||||
} else {
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
})
|
||||
|
||||
// 避免完全不提示,可以在控制台记录被抑制的错误
|
||||
console.log('[错误提示] 已抑制重复错误:', message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return Promise.reject(error)
|
||||
|
||||
}
|
||||
|
||||
34
mining-pool/src/utils/requestWrapper.js
Normal file
34
mining-pool/src/utils/requestWrapper.js
Normal file
@@ -0,0 +1,34 @@
|
||||
//自动记录请求参数,并支持断网重连,创建一个函数装饰器
|
||||
/**
|
||||
* 包装请求方法,自动注册断网重连恢复
|
||||
* @param {Object} component - 组件实例
|
||||
* @param {String} methodName - 方法名
|
||||
* @param {Function} originalMethod - 原始方法
|
||||
* @returns {Function} 包装后的方法
|
||||
*/
|
||||
export function wrapRequestMethod(component, methodName, originalMethod) {
|
||||
return async function(...args) {
|
||||
// 注册为恢复方法(仅当组件支持断网重连恢复)
|
||||
if (component.registerRecoveryMethod) {
|
||||
component.registerRecoveryMethod(methodName, args[0]);
|
||||
}
|
||||
|
||||
// 调用原始方法
|
||||
return await originalMethod.apply(component, args);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动包装组件中的所有请求方法
|
||||
* @param {Object} component - 组件实例
|
||||
* @param {Array<String>} methodNames - 方法名列表
|
||||
*/
|
||||
export function wrapComponentMethods(component, methodNames) {
|
||||
methodNames.forEach(methodName => {
|
||||
if (typeof component[methodName] === 'function') {
|
||||
const originalMethod = component[methodName];
|
||||
component[methodName] = wrapRequestMethod(component, methodName, originalMethod);
|
||||
console.log(`[RequestWrapper] 包装方法: ${methodName}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -171,10 +171,13 @@ export default {
|
||||
// this.stateList = JSON.parse(localStorage.getItem('stateList') )
|
||||
// this.typeList = JSON.parse(localStorage.getItem('typeList') )
|
||||
|
||||
this.registerRecoveryMethod('fetchTicketDetails', { id: this.workOrderId });
|
||||
|
||||
},
|
||||
methods: {
|
||||
async fetchBKendTicket(params){
|
||||
this.totalDetailsLoading =true
|
||||
// this.totalDetailsLoading =true
|
||||
this.setLoading('totalDetailsLoading', true);
|
||||
const data = await getBKendTicket(params)
|
||||
if (data && data.code == 200) {
|
||||
this.$message({
|
||||
@@ -185,11 +188,12 @@ export default {
|
||||
|
||||
}
|
||||
|
||||
this.totalDetailsLoading =false
|
||||
this.setLoading('totalDetailsLoading', false);
|
||||
},
|
||||
|
||||
async fetchReply(params){
|
||||
this.totalDetailsLoading = true
|
||||
// this.totalDetailsLoading = true
|
||||
this.setLoading('totalDetailsLoading', true);
|
||||
const data = await getReply(params)
|
||||
if (data && data.code == 200) {
|
||||
this.$message({
|
||||
@@ -205,7 +209,7 @@ export default {
|
||||
}
|
||||
|
||||
|
||||
this.totalDetailsLoading = false
|
||||
this.setLoading('totalDetailsLoading', false);
|
||||
},
|
||||
handelType2(label){
|
||||
if (label) {
|
||||
@@ -231,14 +235,15 @@ export default {
|
||||
},
|
||||
//请求工单详情
|
||||
async fetchTicketDetails(param) {
|
||||
this.totalDetailsLoading = true
|
||||
// this.totalDetailsLoading = true
|
||||
this.setLoading('totalDetailsLoading', true);
|
||||
const { data } = await getDetails(param)
|
||||
|
||||
this.recordList = data.list
|
||||
this.ticketDetails = data
|
||||
|
||||
|
||||
this.totalDetailsLoading = false
|
||||
this.setLoading('totalDetailsLoading', false);
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ export default {
|
||||
this.params.maId = this.receiveData.id
|
||||
}
|
||||
this.fetchList(this.listParams)
|
||||
|
||||
this.registerRecoveryMethod('fetchList', this.listParams);
|
||||
|
||||
},
|
||||
methods:{
|
||||
@@ -100,7 +100,8 @@ export default {
|
||||
return getImageUrl(path);
|
||||
},
|
||||
async fetchAddNoticeEmail(params){
|
||||
this.addMinerLoading = true
|
||||
// this.addMinerLoading = true
|
||||
this.setLoading('addMinerLoading', true);
|
||||
const data = await getAddNoticeEmail(params)
|
||||
if (data && data.code == 200) {
|
||||
this.$message({
|
||||
@@ -121,17 +122,18 @@ export default {
|
||||
|
||||
}
|
||||
}
|
||||
this.addMinerLoading = false
|
||||
this.setLoading('addMinerLoading', false);
|
||||
|
||||
},
|
||||
async fetchList(params){
|
||||
this.alertsLoading=true
|
||||
// this.alertsLoading=true
|
||||
this.setLoading('alertsLoading', true);
|
||||
const data = await getList(params)
|
||||
if (data && data.code == 200) {
|
||||
this.tableData = data.rows
|
||||
|
||||
}
|
||||
this.alertsLoading=false
|
||||
this.setLoading('alertsLoading', false);
|
||||
|
||||
},
|
||||
async fetchCode(params){
|
||||
@@ -147,7 +149,8 @@ export default {
|
||||
|
||||
},
|
||||
async fetchUpdateInfo(params){
|
||||
this.addMinerLoading = true
|
||||
// this.addMinerLoading = true
|
||||
this.setLoading('addMinerLoading', true);
|
||||
const data = await getUpdateInfo(params)
|
||||
if (data && data.code == 200) {
|
||||
this.$message({
|
||||
@@ -159,11 +162,12 @@ export default {
|
||||
this.fetchList(this.listParams)
|
||||
}
|
||||
|
||||
this.addMinerLoading = false
|
||||
this.setLoading('addMinerLoading', false);
|
||||
|
||||
},
|
||||
async fetchDeleteEmail(params){
|
||||
this.deleteLoading = true
|
||||
// this.deleteLoading = true
|
||||
this.setLoading('deleteLoading', true);
|
||||
const data = await deleteEmail(params)
|
||||
if (data && data.code == 200) {
|
||||
this.$message({
|
||||
@@ -175,7 +179,7 @@ export default {
|
||||
this.fetchList(this.listParams)
|
||||
}
|
||||
|
||||
this.deleteLoading = false
|
||||
this.setLoading('deleteLoading', false);
|
||||
|
||||
},
|
||||
|
||||
|
||||
@@ -442,7 +442,7 @@
|
||||
<!-- 挖矿账号下矿工总览 -->
|
||||
<div class="Pool">
|
||||
<p class="hash">{{ $t(`apiFile.overviewOfMiners`) }}</p>
|
||||
<p class="Interface">Post /oapi/v1/account/miners_list</p>
|
||||
<p class="Interface">Post /oapi/v1/account/watch</p>
|
||||
<p class="hash">{{ $t(`apiFile.jurisdiction`) }} account</p>
|
||||
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
||||
<table border="1">
|
||||
@@ -797,7 +797,7 @@
|
||||
<!-- 指定矿机历史24h平均算力 -->
|
||||
<div class="Pool">
|
||||
<p class="hash">{{ $t(`apiFile.miningMachineHistory24h`) }}</p>
|
||||
<p class="Interface">Post /oapi/v1/miner/hashrate_history</p>
|
||||
<p class="Interface">Post /oapi/v1/miner/hashrate_history</p>
|
||||
<p class="hash">{{ $t(`apiFile.jurisdiction`) }} miner</p>
|
||||
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
||||
<table border="1">
|
||||
@@ -1371,7 +1371,7 @@
|
||||
<!-- 挖矿账号下矿工总览 -->
|
||||
<div class="Pool">
|
||||
<p class="hash">{{ $t(`apiFile.overviewOfMiners`) }}</p>
|
||||
<p class="Interface">Post /oapi/v1/account/miners_list</p>
|
||||
<p class="Interface">Post /oapi/v1/account/watch </p>
|
||||
<p class="hash">{{ $t(`apiFile.jurisdiction`) }} account</p>
|
||||
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
||||
<table border="1">
|
||||
@@ -1726,7 +1726,7 @@
|
||||
<!-- 指定矿机历史24h平均算力 -->
|
||||
<div class="Pool">
|
||||
<p class="hash">{{ $t(`apiFile.miningMachineHistory24h`) }}</p>
|
||||
<p class="Interface">Get /oapi/v1/miner/hashrate_history</p>
|
||||
<p class="Interface">Post /oapi/v1/miner/hashrate_history</p>
|
||||
<p class="hash">{{ $t(`apiFile.jurisdiction`) }} miner</p>
|
||||
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
||||
<table border="1">
|
||||
|
||||
0
mining-pool/src/views/customerService/index.js
Normal file
0
mining-pool/src/views/customerService/index.js
Normal file
1044
mining-pool/src/views/customerService/index.vue
Normal file
1044
mining-pool/src/views/customerService/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -759,7 +759,7 @@ export default {
|
||||
],
|
||||
FeeShow: true,
|
||||
lang: 'en',
|
||||
activeItemCoin:{
|
||||
activeItemCoin: {
|
||||
value: "nexa",
|
||||
label: "nexa",
|
||||
img: require("../../assets/img/currency-nexa.png"),
|
||||
@@ -781,14 +781,14 @@ export default {
|
||||
},
|
||||
activeItemCoin: {
|
||||
handler(newVal) {
|
||||
// 防止无限循环
|
||||
if (this.isInternalChange) {
|
||||
return;
|
||||
}
|
||||
this.handleActiveItemChange(newVal);
|
||||
// 防止无限循环
|
||||
if (this.isInternalChange) {
|
||||
return;
|
||||
}
|
||||
this.handleActiveItemChange(newVal);
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -832,6 +832,11 @@ export default {
|
||||
this.getCoinInfoData(this.params)
|
||||
this.getPoolPowerData(this.PowerParams)
|
||||
|
||||
// 注册需要在网络恢复后自动重新调用的方法
|
||||
this.registerRecoveryMethod('getCoinInfoData', this.params);
|
||||
this.registerRecoveryMethod('getPoolPowerData', this.PowerParams);
|
||||
this.registerRecoveryMethod('getBlockInfoData', this.BlockInfoParams);
|
||||
|
||||
this.$addStorageEvent(1, `currencyList`, JSON.stringify(this.currencyList))
|
||||
if (this.$refs.select) {
|
||||
this.$refs.select.$el.children[0].children[0].setAttribute('style', "background:url(https://test.m2pool.com/img/nexa.png) no-repeat 10PX;background-size: 20PX 20PX;color:#333;padding-left: 30PX;");
|
||||
@@ -844,8 +849,8 @@ export default {
|
||||
// let activeItemCoin =localStorage.getItem(`activeItemCoin`)
|
||||
// this.activeItemCoin=JSON.parse(activeItemCoin)
|
||||
window.addEventListener("setItem", () => {
|
||||
let value =localStorage.getItem(`activeItemCoin`)
|
||||
this.activeItemCoin=JSON.parse(value)
|
||||
let value = localStorage.getItem(`activeItemCoin`)
|
||||
this.activeItemCoin = JSON.parse(value)
|
||||
|
||||
});
|
||||
|
||||
@@ -1082,12 +1087,12 @@ export default {
|
||||
this.inCharts()
|
||||
})
|
||||
|
||||
}catch{
|
||||
} catch {
|
||||
console.error('获取数据失败:', error);
|
||||
}finally {
|
||||
} finally {
|
||||
// 确保无论成功失败都设置loading为false
|
||||
this.setLoading('minerChartLoading', false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1221,37 +1226,11 @@ export default {
|
||||
|
||||
}, 200),
|
||||
|
||||
// async getBlockInfoData(params) {
|
||||
// this.reportBlockLoading = true
|
||||
// const data = await getBlockInfo(params)
|
||||
// if (data && data.code == 200) {
|
||||
// this.BlockShow = true
|
||||
// this.newBlockInfoData = []
|
||||
// this.BlockInfoData = data.rows
|
||||
// if (!this.BlockInfoData[0]) {
|
||||
// this.reportBlockLoading = false
|
||||
// return
|
||||
// }
|
||||
|
||||
|
||||
// this.BlockInfoData.forEach((item, index) => {
|
||||
// item.date = `${item.date.split("T")[0]} ${item.date.split("T")[1].split(`.`)[0]}`
|
||||
// if (index < 8) {
|
||||
// this.newBlockInfoData.push(item)
|
||||
// }
|
||||
// })
|
||||
|
||||
|
||||
|
||||
// } else {
|
||||
// this.BlockShow = false
|
||||
// }
|
||||
|
||||
// this.reportBlockLoading = false
|
||||
// },
|
||||
|
||||
getBlockInfoData: Debounce(async function (params) {
|
||||
// this.reportBlockLoading = true
|
||||
try {
|
||||
// this.reportBlockLoading = true
|
||||
this.setLoading('reportBlockLoading', true);
|
||||
const data = await getBlockInfo(params)
|
||||
if (data && data.code == 200) {
|
||||
@@ -1259,7 +1238,8 @@ export default {
|
||||
this.newBlockInfoData = []
|
||||
this.BlockInfoData = data.rows
|
||||
if (!this.BlockInfoData[0]) {
|
||||
this.reportBlockLoading = false
|
||||
// this.reportBlockLoading = false
|
||||
this.setLoading('reportBlockLoading', false);
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1271,13 +1251,21 @@ export default {
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
this.BlockShow = false
|
||||
}
|
||||
this.setLoading('reportBlockLoading', false);
|
||||
// this.reportBlockLoading = false
|
||||
} catch (error) {
|
||||
console.error('获取区块信息失败:', error);
|
||||
this.BlockShow = false;
|
||||
}finally {
|
||||
// 确保在任何情况下都会重置 loading 状态
|
||||
this.setLoading('reportBlockLoading', false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1321,39 +1309,55 @@ export default {
|
||||
|
||||
switch (this.time) {
|
||||
case "day":
|
||||
// this.profit = result.toFixed(10)
|
||||
this.profit = result.toFixed(8)
|
||||
// this.profit = Math.floor(result * 1e10) / 1e10;
|
||||
this.profit = this.toFixedNoRound(result, 10);
|
||||
// this.profit = this.toFixedNoRound(result, 10);
|
||||
break;
|
||||
case "week":
|
||||
// this.profit = (result * 7).toFixed(10)
|
||||
this.profit = (result * 7).toFixed(8)
|
||||
// this.profit = Math.floor(result * 7 * 1e10) / 1e10;
|
||||
this.profit = this.toFixedNoRound(result * 7, 10);
|
||||
// this.profit = this.toFixedNoRound(result * 7, 10);
|
||||
break;
|
||||
case "month":
|
||||
// this.profit = (result * 30).toFixed(10)
|
||||
this.profit = (result * 30).toFixed(8)
|
||||
// this.profit = Math.floor(result * 30 * 1e10) / 1e10;
|
||||
this.profit = this.toFixedNoRound(result * 30, 10);
|
||||
// this.profit = this.toFixedNoRound(result * 30, 10);
|
||||
break;
|
||||
case "year":
|
||||
// this.profit = (result * 365).toFixed(10)
|
||||
this.profit = (result * 365).toFixed(8)
|
||||
// this.profit = Math.floor(result * 365 * 1e10) / 1e10;
|
||||
this.profit = this.toFixedNoRound(result * 365, 10);
|
||||
// this.profit = this.toFixedNoRound(result * 365, 10);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 10000000000000000
|
||||
|
||||
const formatter = new Intl.NumberFormat("en-US", {
|
||||
minimumFractionDigits: 10, // 强制显示足够多的小数位
|
||||
const nexaFormatter = new Intl.NumberFormat("en-US", {
|
||||
minimumFractionDigits: 2, // 强制显示 2 位小数(不足补零)
|
||||
maximumFractionDigits: 2, // 可选:限制最多 2 位小数(避免多余位数)
|
||||
useGrouping: true, // 不使用千位分隔符(如 1,000)
|
||||
});
|
||||
this.profit = formatter.format(this.profit);
|
||||
if (this.value == "nexa") {
|
||||
this.profit = nexaFormatter.format(this.profit);
|
||||
} else {
|
||||
const formatter = new Intl.NumberFormat("en-US", {
|
||||
minimumFractionDigits: 8, // 强制显示足够多的小数位
|
||||
useGrouping: true, // 不使用千位分隔符(如 1,000)
|
||||
});
|
||||
|
||||
|
||||
this.profit = formatter.format(this.profit);
|
||||
}
|
||||
|
||||
|
||||
// const formatter = new Intl.NumberFormat("en-US", {
|
||||
// minimumFractionDigits: 8, // 强制显示足够多的小数位
|
||||
// useGrouping: false, // 不使用千位分隔符(如 1,000)
|
||||
// });
|
||||
|
||||
|
||||
// this.profit = formatter.format(this.profit);
|
||||
|
||||
|
||||
},
|
||||
toFixedNoRound(value, decimals = 10) {//保留10位小数 不四舍五入
|
||||
@@ -1425,14 +1429,14 @@ export default {
|
||||
let jumpName = coin.path.charAt(0).toUpperCase() + coin.path.slice(1) //name跳转 首字母大写
|
||||
// 使用 name 进行导航,避免重复的路由参数
|
||||
this.$router.push({
|
||||
name: jumpName,
|
||||
params: {
|
||||
lang: this.lang,
|
||||
coin: this.params.coin,
|
||||
imgUrl: this.currencyPath
|
||||
name: jumpName,
|
||||
params: {
|
||||
lang: this.lang,
|
||||
coin: this.params.coin,
|
||||
imgUrl: this.currencyPath
|
||||
|
||||
},
|
||||
replace: false // 保留历史记录,允许回退
|
||||
},
|
||||
replace: false // 保留历史记录,允许回退
|
||||
});
|
||||
|
||||
} else {
|
||||
@@ -1499,7 +1503,7 @@ export default {
|
||||
this.currencyPath = item.imgUrl;
|
||||
this.params.coin = item.value;
|
||||
|
||||
console.log( this.params.coin , "item");
|
||||
console.log(this.params.coin, "item");
|
||||
this.BlockInfoParams.coin = item.value;
|
||||
this.itemActive = item.value;
|
||||
this.PowerParams.coin = item.value;
|
||||
@@ -1509,13 +1513,13 @@ export default {
|
||||
this.getBlockInfoData(this.BlockInfoParams);
|
||||
|
||||
if (this.powerActive) {
|
||||
this.handelPower();
|
||||
this.handelPower();
|
||||
} else {
|
||||
this.handelMiner();
|
||||
this.handelMiner();
|
||||
}
|
||||
|
||||
this.handelCoinLabel(item.value);
|
||||
},
|
||||
},
|
||||
|
||||
clickCurrency(item) {
|
||||
if (!item) return;
|
||||
@@ -1538,8 +1542,8 @@ export default {
|
||||
});
|
||||
|
||||
|
||||
// 直接调用处理方法
|
||||
this.handleActiveItemChange(item);
|
||||
// 直接调用处理方法
|
||||
this.handleActiveItemChange(item);
|
||||
|
||||
},
|
||||
clickReportBlock() {
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<section v-if="$isMobile">
|
||||
|
||||
<div class="imgTop">
|
||||
<!-- <img src="../../assets/mobile/home/home.png" alt="mining" loading="lazy" /> -->
|
||||
|
||||
<img src="../../assets/mobile/home/home.png" alt="mining" loading="lazy" />
|
||||
<!--
|
||||
<img v-if="lang == 'zh'" src="../../assets/img/enx推广.png" alt="mining" loading="lazy"/>
|
||||
<img v-else src="../../assets/img/enx英文推广.png" alt="mining" loading="lazy"/>
|
||||
<img v-else src="../../assets/img/enx英文推广.png" alt="mining" loading="lazy"/> -->
|
||||
|
||||
</div>
|
||||
|
||||
@@ -329,13 +329,12 @@
|
||||
|
||||
</section>
|
||||
<div class="content" v-else v-loading="minerChartLoading">
|
||||
|
||||
<div class="bgBox">
|
||||
|
||||
<!--
|
||||
<img v-if="lang == 'zh'" class="bgBoxImg2Img" src="../../assets/img/enx推广.png" alt="mining" loading="lazy"/>
|
||||
<img v-else class="bgBoxImg2Img" src="../../assets/img/enx英文推广.png" alt="mining" loading="lazy"/>
|
||||
|
||||
|
||||
<!-- <img class="bgBoxImg" src="../../assets/img/enx推广.png" style="width: 100%;height: 100%;" alt="mining" loading="lazy"/> -->
|
||||
<img v-else class="bgBoxImg2Img" src="../../assets/img/enx英文推广.png" alt="mining" loading="lazy"/> -->
|
||||
<img class="bgImg" src="../../assets/img/home.png" alt="mining" loading="lazy"/>
|
||||
</div>
|
||||
<el-row>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
@@ -375,7 +374,7 @@
|
||||
<div class="currencyDescription2">
|
||||
<section class="miningPoolBox">
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
|
||||
<div class="miningPoolLeft" v-loading="minerChartLoading">
|
||||
<div class="miningPoolLeft" v-loading="minerChartLoading" v-loading-recovery="{ loading: 'minerChartLoading', recovery: ['getPoolPowerData', 'fetchNetPower'] }">
|
||||
<div class="interval">
|
||||
<div class="chartBth">
|
||||
|
||||
@@ -603,7 +602,7 @@
|
||||
<el-row>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||
<div class="reportBlock">
|
||||
<div class="reportBlockBox" v-loading="reportBlockLoading">
|
||||
<div class="reportBlockBox" v-loading="reportBlockLoading" v-loading-recovery="{ loading: 'reportBlockLoading', recovery: ['getBlockInfoData'] }">
|
||||
<div class="belowTable">
|
||||
<ul>
|
||||
<li class="table-title">
|
||||
@@ -785,6 +784,7 @@ export default {
|
||||
p{
|
||||
width: 100% ;
|
||||
background: transparent ;
|
||||
padding-left: 8px;
|
||||
|
||||
}
|
||||
i{
|
||||
@@ -1295,16 +1295,44 @@ export default {
|
||||
@media screen and (min-width:800px) and (max-width: 1279px) {
|
||||
.imgTop {
|
||||
width: 100%;
|
||||
// padding-left: 10%;
|
||||
text-align: center;
|
||||
padding-left: 20%;
|
||||
text-align: left;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
width: auto ;
|
||||
height:300px;
|
||||
}
|
||||
}
|
||||
#chart {
|
||||
height: 400px !important;
|
||||
}
|
||||
.describeBox2{
|
||||
width: 100%;
|
||||
font-size: 0.9rem;
|
||||
padding: 8px;
|
||||
margin: 0 auto;
|
||||
p{
|
||||
width: 100% ;
|
||||
background: transparent ;
|
||||
padding-left: 8px;
|
||||
|
||||
}
|
||||
i{
|
||||
color: #5721e4;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.describeTitle{
|
||||
color: #5721e4;
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.view{
|
||||
color: #5721e4;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.moveCurrencyBox {
|
||||
@@ -2046,7 +2074,7 @@ export default {
|
||||
.bgBox {
|
||||
// background: gold;
|
||||
width: 100%;
|
||||
// height: 380px;
|
||||
height: 300px;
|
||||
box-sizing: border-box;
|
||||
// background-position: 50% 28%;
|
||||
// background-size: cover;
|
||||
@@ -2059,12 +2087,20 @@ export default {
|
||||
// background-position: 13.2vw 0 ;
|
||||
// background-repeat: no-repeat;
|
||||
// margin-top: 50px;
|
||||
margin: 30px 0px;
|
||||
// margin: 30px 0px;
|
||||
|
||||
text-align: center;
|
||||
text-align: left;
|
||||
.bgImg{
|
||||
height: 100%;
|
||||
width: auto ;
|
||||
position: absolute;
|
||||
left: 25vw;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.bgBoxImg {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
position: absolute;
|
||||
left: 23%;
|
||||
transition: all 0.3s linear;
|
||||
|
||||
@@ -1346,6 +1346,13 @@ export default {
|
||||
this.getHistoryIncomeData(this.IncomeParams)
|
||||
this.getHistoryOutcomeData(this.OutcomeParams)
|
||||
|
||||
|
||||
this.registerRecoveryMethod('getMinerAccountInfoData', this.params);
|
||||
this.registerRecoveryMethod('getMinerAccountPowerData', this.PowerParams);
|
||||
this.registerRecoveryMethod('getAccountPowerDistributionData', this.PowerDistribution);
|
||||
this.registerRecoveryMethod('getMinerListData', this.MinerListParams);
|
||||
this.registerRecoveryMethod('getHistoryIncomeData', this.IncomeParams);
|
||||
this.registerRecoveryMethod('getHistoryOutcomeData', this.OutcomeParams);
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -1400,11 +1407,12 @@ export default {
|
||||
// console.log(data,"获取币种信息");
|
||||
},
|
||||
async getMinerAccountPowerData(params) {
|
||||
this.powerChartLoading = true
|
||||
// this.powerChartLoading = true
|
||||
this.setLoading('powerChartLoading', true);
|
||||
const data = await getMinerAccountPower(params)
|
||||
|
||||
if (!data) {
|
||||
this.powerChartLoading = false
|
||||
this.setLoading('powerChartLoading', false);
|
||||
if (this.myChart) {
|
||||
this.myChart.dispose()//销毁图表实列
|
||||
}
|
||||
@@ -1437,13 +1445,13 @@ export default {
|
||||
this.option.series[1].data = rejectRate
|
||||
|
||||
this.inCharts()
|
||||
this.powerChartLoading = false
|
||||
this.setLoading('powerChartLoading', false);
|
||||
|
||||
|
||||
|
||||
},
|
||||
async getAccountPowerDistributionData(params) {
|
||||
this.barChartLoading = true
|
||||
this.setLoading('barChartLoading', true);
|
||||
const data = await getAccountPowerDistribution(params)
|
||||
let barData = data.data
|
||||
let xData = []
|
||||
@@ -1455,7 +1463,7 @@ export default {
|
||||
this.barOption.xAxis[0].data = xData
|
||||
this.barOption.series[0].data = barValueList
|
||||
this.barInCharts()
|
||||
this.barChartLoading = false
|
||||
this.setLoading('barChartLoading', false);
|
||||
},
|
||||
formatNumber(num) {//保留两位小数并补0
|
||||
const intPart = Math.floor(num);
|
||||
@@ -1463,7 +1471,7 @@ export default {
|
||||
return `${intPart}.${String(decimalPart).padStart(2, '0')}`;
|
||||
},
|
||||
async getMinerListData(params) {
|
||||
this.MinerListLoading = true
|
||||
this.setLoading('MinerListLoading', true);
|
||||
const data = await getMinerList(params)
|
||||
if (data && data.code == 200) {
|
||||
this.MinerListData = data.data
|
||||
@@ -1503,7 +1511,7 @@ export default {
|
||||
|
||||
}
|
||||
|
||||
this.MinerListLoading = false
|
||||
this.setLoading('MinerListLoading', false);
|
||||
|
||||
},
|
||||
|
||||
@@ -1562,11 +1570,11 @@ export default {
|
||||
// this.miniLoading=false
|
||||
// },
|
||||
getMinerPowerData:Debounce(async function(params){
|
||||
this.miniLoading=true
|
||||
this.setLoading('miniLoading', true);
|
||||
const data = await getMinerPower(params)
|
||||
|
||||
if (!data) {
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
return
|
||||
}
|
||||
let miniData = data.data
|
||||
@@ -1618,62 +1626,18 @@ export default {
|
||||
|
||||
|
||||
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
},200),
|
||||
//小图
|
||||
// async getMinerPowerOnLine(params) {
|
||||
// this.miniLoading=true
|
||||
// const data = await getMinerPower(params)
|
||||
|
||||
// if (!data) {
|
||||
// this.miniLoading=false
|
||||
// return
|
||||
// }
|
||||
// let miniData = data.data
|
||||
// let xData = []
|
||||
// let pv = []
|
||||
// let rejectRate = []
|
||||
|
||||
// miniData.forEach(item => {
|
||||
// if (item.date.includes(`T`)) {
|
||||
// xData.push(`${item.date.split("T")[0]} ${item.date.split("T")[1].split(".")[0]}` )
|
||||
|
||||
// } else {
|
||||
// xData.push(item.date)
|
||||
// }
|
||||
|
||||
// pv.push(item.pv.toFixed(2))
|
||||
// rejectRate.push((item.rejectRate * 100).toFixed(4))
|
||||
// })
|
||||
|
||||
|
||||
// this.onLineOption.xAxis.data = xData
|
||||
// this.onLineOption.series[0].data = pv
|
||||
// this.onLineOption.series[1].data = rejectRate
|
||||
// this.onLineOption.series[0].name= this.$t(`home.finallyPower`)
|
||||
// this.onLineOption.series[1].name= this.$t(`home.rejectionRate`)
|
||||
|
||||
// this.ids = `Small${this.miniId}`
|
||||
// this.miniChartOnLine = echarts.init(document.getElementById(this.ids))
|
||||
|
||||
// this.$nextTick(() => {
|
||||
// this.miniChartOnLine.setOption(this.onLineOption,true);
|
||||
// window.addEventListener("resize", () => {
|
||||
// if (this.miniChartOnLine) this.miniChartOnLine.resize();
|
||||
// });
|
||||
// });
|
||||
|
||||
|
||||
|
||||
// this.miniLoading=false
|
||||
// },
|
||||
getMinerPowerOnLine:Debounce(async function(params){
|
||||
|
||||
this.miniLoading=true
|
||||
this.setLoading('miniLoading', true);
|
||||
const data = await getMinerPower(params)
|
||||
|
||||
if (!data) {
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
return
|
||||
}
|
||||
let miniData = data.data
|
||||
@@ -1716,7 +1680,7 @@ export default {
|
||||
|
||||
|
||||
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
|
||||
|
||||
},200),
|
||||
@@ -1768,10 +1732,10 @@ export default {
|
||||
// this.miniLoading=false
|
||||
// },
|
||||
getMinerPowerOffLine:Debounce(async function(params){
|
||||
this.miniLoading=true
|
||||
this.setLoading('miniLoading', true);
|
||||
const data = await getMinerPower(params)
|
||||
if (!data) {
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
return
|
||||
}
|
||||
let miniData = data.data
|
||||
@@ -1815,7 +1779,7 @@ export default {
|
||||
|
||||
|
||||
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
|
||||
|
||||
},200),
|
||||
|
||||
@@ -96,17 +96,20 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.fetchApiList(this.listParams)
|
||||
this.registerRecoveryMethod('fetchApiList', this.listParams);
|
||||
|
||||
},
|
||||
methods: {
|
||||
async fetchApiKey(params) {
|
||||
this.ApiKeyLoading = true
|
||||
this.setLoading('ApiKeyLoading', true);
|
||||
const data = await getApiKey(params)
|
||||
if (data && data.code == 200) {
|
||||
this.fetchApiList(this.listParams)
|
||||
this.dialogVisible = false
|
||||
}
|
||||
|
||||
this.ApiKeyLoading = false
|
||||
this.setLoading('ApiKeyLoading', false);
|
||||
},
|
||||
async fetchApiList(params) {
|
||||
this.apiPageLoading = true
|
||||
@@ -115,7 +118,7 @@ export default {
|
||||
this.apiList = data.rows
|
||||
}
|
||||
|
||||
this.apiPageLoading = false
|
||||
this.setLoading('apiPageLoading', false);
|
||||
},
|
||||
async fetchApiInfo(params) {
|
||||
this.apiPageLoading = true
|
||||
@@ -127,7 +130,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
this.apiPageLoading = false
|
||||
this.setLoading('apiPageLoading', false);
|
||||
},
|
||||
async fetchUpdateAPI(params) {
|
||||
this.apiPageLoading = true
|
||||
@@ -137,7 +140,7 @@ export default {
|
||||
this.modifyDialogVisible =false
|
||||
}
|
||||
|
||||
this.apiPageLoading = false
|
||||
this.setLoading('apiPageLoading', false);
|
||||
},
|
||||
async fetchDelApi(params) {
|
||||
this.apiPageLoading = true
|
||||
@@ -149,7 +152,7 @@ export default {
|
||||
this.fetchApiList(this.listParams)
|
||||
}
|
||||
|
||||
this.apiPageLoading = false
|
||||
this.setLoading('apiPageLoading', false);
|
||||
},
|
||||
RequestApiKey() {
|
||||
this.dialogVisible = true
|
||||
|
||||
@@ -270,6 +270,9 @@ export default {
|
||||
|
||||
this.fetchAccountList()
|
||||
|
||||
this.registerRecoveryMethod('fetchIfBind', "");
|
||||
this.registerRecoveryMethod('fetchAccountList', "");
|
||||
|
||||
this.currencyList = JSON.parse(localStorage.getItem("currencyList"))
|
||||
window.addEventListener("setItem", () => {
|
||||
this.currencyList = JSON.parse(localStorage.getItem("currencyList"))
|
||||
@@ -284,7 +287,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async fetchIfBind(params){
|
||||
this.securityLoading = true
|
||||
// this.securityLoading = true
|
||||
this.setLoading('securityLoading', true);
|
||||
const data = await getIfBind(params)
|
||||
if (data && data.code === 200) {
|
||||
if (data.data) {
|
||||
@@ -302,13 +306,14 @@ export default {
|
||||
this.dialogVerification=true
|
||||
}
|
||||
}
|
||||
this.securityLoading = false
|
||||
this.setLoading('securityLoading', false);
|
||||
},
|
||||
async fetchCheck(params){
|
||||
this.addMinerLoading =true
|
||||
// this.addMinerLoading =true
|
||||
this.setLoading('addMinerLoading', true);
|
||||
const data = await getCheck(params)
|
||||
if (!data) {
|
||||
this.addMinerLoading =false
|
||||
this.setLoading('addMinerLoading', false);
|
||||
|
||||
}
|
||||
if (data && data.code === 200) {
|
||||
@@ -320,20 +325,21 @@ export default {
|
||||
type: "error",
|
||||
showClose: true
|
||||
});
|
||||
this.addMinerLoading =false
|
||||
this.setLoading('addMinerLoading', false);
|
||||
}else if(data.code === 802){//钱包不可用
|
||||
this.$message({
|
||||
message: this.$t(`personal.invalidAddress`),
|
||||
type: "error",
|
||||
showClose: true
|
||||
});
|
||||
this.addMinerLoading =false
|
||||
this.setLoading('addMinerLoading', false);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
async fetchCheckBalance(params){
|
||||
this.confirmBindingLoading =true
|
||||
// this.confirmBindingLoading =true
|
||||
this.setLoading('confirmBindingLoading', true);
|
||||
const data = await getCheckBalance(params)
|
||||
if (data && data.data) {
|
||||
this.fetchWalletAddress(this.WalletAddressParams)
|
||||
@@ -344,7 +350,7 @@ export default {
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
this.confirmBindingLoading =false
|
||||
this.setLoading('confirmBindingLoading', false);
|
||||
},
|
||||
async fetchAccountGradeList(){
|
||||
const data = await getAccountGradeList()
|
||||
@@ -369,7 +375,8 @@ export default {
|
||||
}
|
||||
},
|
||||
async fetchMinerAccountBalance(params) {
|
||||
this.MiningLoading = true
|
||||
// this.MiningLoading = true
|
||||
this.setLoading('MiningLoading', true);
|
||||
const data = await getMinerAccountBalance(params)
|
||||
if (data && data.code == 200) {
|
||||
this.walletDialogVisible = true
|
||||
@@ -386,10 +393,11 @@ export default {
|
||||
this.paymentSettingsData.active = this.paymentSettingsData.active==`1` ? this.$t(`personal.no`) :this.$t(`personal.yes`)
|
||||
|
||||
this.paymentSettingsData.amount = this.paymentSettingsData.amount ? this.paymentSettingsData.amount : `0`
|
||||
this.MiningLoading = false
|
||||
this.setLoading('MiningLoading', false);
|
||||
},
|
||||
async fetchDelMinerAccount(params) {
|
||||
this.MiningLoading = true
|
||||
// this.MiningLoading = true
|
||||
this.setLoading('MiningLoading', true);
|
||||
const data = await getDelMinerAccount(params)
|
||||
|
||||
if (data && data.code == 200) {
|
||||
@@ -400,17 +408,18 @@ export default {
|
||||
|
||||
|
||||
}
|
||||
this.MiningLoading = false
|
||||
this.setLoading('MiningLoading', false);
|
||||
},
|
||||
async fetchAccountList(params) {
|
||||
this.MiningLoading = true
|
||||
// this.MiningLoading = true
|
||||
this.setLoading('MiningLoading', true);
|
||||
const data = await getAccountList(params)
|
||||
this.accountList = data.data
|
||||
console.log("请求成功,",data);
|
||||
this.newAccountList = this.accountList
|
||||
this.$addStorageEvent(1, `accountList`, JSON.stringify(this.accountList))
|
||||
|
||||
this.MiningLoading = false
|
||||
this.setLoading('MiningLoading', false);
|
||||
|
||||
},
|
||||
|
||||
@@ -431,7 +440,8 @@ export default {
|
||||
},
|
||||
//添加挖矿账户
|
||||
async fetchAddMinerAccount(params) {
|
||||
this.addMinerLoading =true
|
||||
// this.addMinerLoading =true
|
||||
this.setLoading('addMinerLoading', true);
|
||||
const data = await getAddMinerAccount(params)
|
||||
if (data && data.code == 200) {
|
||||
this.$message({
|
||||
@@ -451,7 +461,7 @@ export default {
|
||||
this.fetchAccountList()
|
||||
this.fetchAccountGradeList()
|
||||
|
||||
this.addMinerLoading =false
|
||||
this.setLoading('addMinerLoading', false);
|
||||
},
|
||||
handleCheckAllChange(val) {
|
||||
|
||||
|
||||
@@ -197,14 +197,16 @@ export default {
|
||||
}))
|
||||
}));
|
||||
|
||||
console.log( this.newMiningAccountList,"isrjiojfeo");
|
||||
|
||||
|
||||
|
||||
this.fetchUrlList(this.UrlListParams)
|
||||
this.registerRecoveryMethod('fetchUrlList', this.UrlListParams);
|
||||
},
|
||||
methods: {
|
||||
async fetchHtmlUrl(params){
|
||||
this.establishLoading = true
|
||||
// this.establishLoading = true
|
||||
this.setLoading('establishLoading', true);
|
||||
const data = await getHtmlUrl(params)
|
||||
|
||||
if (data && data.code == 200) {
|
||||
@@ -212,10 +214,11 @@ export default {
|
||||
this.dialogVisible=false
|
||||
}
|
||||
|
||||
this.establishLoading = false
|
||||
this.setLoading('establishLoading', false);
|
||||
},
|
||||
async fetchUrlList(params){
|
||||
this.UrlListLoading = true
|
||||
// this.UrlListLoading = true
|
||||
this.setLoading('UrlListLoading', true);
|
||||
const data = await getUrlList(params)
|
||||
console.log(data,666 );
|
||||
|
||||
@@ -223,7 +226,7 @@ export default {
|
||||
|
||||
this.TotalSize = data.total
|
||||
|
||||
this.UrlListLoading = false
|
||||
this.setLoading('UrlListLoading', false);
|
||||
},
|
||||
async fetchUrlInfo(params){
|
||||
const data = await getUrlInfo(params)
|
||||
@@ -239,7 +242,8 @@ export default {
|
||||
|
||||
},
|
||||
async fetchChangeUrlInfo(params){
|
||||
this.modifyLoading=true
|
||||
// this.modifyLoading=true
|
||||
this.setLoading('modifyLoading', true);
|
||||
const data = await getChangeUrlInfo(params)
|
||||
console.log(data);
|
||||
if (data && data.code == 200) {
|
||||
@@ -248,7 +252,7 @@ export default {
|
||||
console.log("修改成功");
|
||||
|
||||
}
|
||||
this.modifyLoading=false
|
||||
this.setLoading('modifyLoading', false);
|
||||
|
||||
},
|
||||
async fetchDelete(params){
|
||||
|
||||
@@ -155,13 +155,14 @@ export default {
|
||||
|
||||
this.lang = this.$i18n.locale; // 初始化语言值
|
||||
this.fetchIfBind()
|
||||
this.registerRecoveryMethod('fetchIfBind', "");
|
||||
if (this.$route.params.active) {
|
||||
this.handelVerification()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async fetchIfBind(params) {
|
||||
this.securityLoading = true
|
||||
this.setLoading('securityLoading', true);
|
||||
const data = await getIfBind(params)
|
||||
if (data && data.code === 200) {
|
||||
if (data.data) {
|
||||
@@ -170,10 +171,10 @@ export default {
|
||||
this.isItBound = false
|
||||
}
|
||||
}
|
||||
this.securityLoading = false
|
||||
this.setLoading('securityLoading', false);
|
||||
},
|
||||
async fetchBindInfo(params) {
|
||||
this.BindInfoLoading = true
|
||||
this.setLoading('BindInfoLoading', true);
|
||||
const data = await getBindInfo(params)
|
||||
console.log(data, "绑定信息");
|
||||
if (data && data.code === 200) {
|
||||
@@ -182,10 +183,10 @@ export default {
|
||||
this.dialogVisible = false
|
||||
}
|
||||
|
||||
this.BindInfoLoading = false
|
||||
this.setLoading('BindInfoLoading', false);
|
||||
},
|
||||
async fetchBindGoogle(params) {
|
||||
this.BindInfoLoading = true
|
||||
this.setLoading('BindInfoLoading', true);
|
||||
const data = await getBindGoogle(params)
|
||||
console.log(data, "绑定");
|
||||
if (data && data.code === 200) {
|
||||
@@ -203,7 +204,7 @@ export default {
|
||||
|
||||
|
||||
}
|
||||
this.BindInfoLoading = false
|
||||
this.setLoading('BindInfoLoading', false);
|
||||
},
|
||||
async fetchBindCode(params) {
|
||||
const data = await getBindCode(params)
|
||||
@@ -216,7 +217,7 @@ export default {
|
||||
}
|
||||
},
|
||||
async fetchResetPwd(params) {
|
||||
this.ResetPwdLoading = true
|
||||
this.setLoading('ResetPwdLoading', true);
|
||||
const data = await getUpdatePwd(params)
|
||||
if (data && data.code === 200) {
|
||||
this.$message({
|
||||
@@ -230,7 +231,7 @@ export default {
|
||||
localStorage.removeItem("token")
|
||||
this.$router.push(`/${lang}/login`);
|
||||
}
|
||||
this.ResetPwdLoading = false
|
||||
this.setLoading('ResetPwdLoading', false);
|
||||
},
|
||||
async fetchResetPwdCode(params) {
|
||||
const data = await getUpdatePwdCode(params)
|
||||
@@ -244,7 +245,7 @@ export default {
|
||||
|
||||
},
|
||||
async fetchCloseStepTwo(params) {
|
||||
this.closeLoading = true
|
||||
this.setLoading('closeLoading', true);
|
||||
const data = await getCloseStepTwo(params)
|
||||
if (data && data.code === 200) {
|
||||
this.$message({
|
||||
@@ -260,7 +261,7 @@ export default {
|
||||
this.closeParams[key] = ""
|
||||
}
|
||||
}
|
||||
this.closeLoading = false
|
||||
this.setLoading('closeLoading', false);
|
||||
},
|
||||
async fetchCloseCode(params) {
|
||||
const data = await getCloseCode(params)
|
||||
|
||||
@@ -69,7 +69,7 @@ export default {
|
||||
value:"enx",
|
||||
label:"Entropyx(Enx)",
|
||||
img:`${this.$baseApi}img/enx.svg`,
|
||||
rate:"0",
|
||||
rate:"1%",
|
||||
address:"",
|
||||
mode:"PPLNS+PROPDIF",
|
||||
quota:"5000",
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
<template slot="title">
|
||||
<div class="collapseTitle">
|
||||
<span ><img :src="item.img" alt="coin" loading="lazy"> {{item.label}}</span>
|
||||
<span v-if="item.value === 'enx'"> {{ $t(`course.timeLimited`) }} 0%</span>
|
||||
<span v-else>{{item.rate}}</span>
|
||||
<!-- <span v-if="item.value === 'enx'"> {{ $t(`course.timeLimited`) }} 0%</span> -->
|
||||
<span >{{item.rate}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<section class="contentBox2">
|
||||
@@ -76,8 +76,8 @@
|
||||
<li v-for="item in rateList" :key="item.value">
|
||||
<span class="coin"><img :src="item.img" alt="coin" loading="lazy"> {{item.label}}</span>
|
||||
<span>{{item.address}}</span>
|
||||
<span v-if="item.value === 'enx'"> {{ $t(`course.timeLimited`) }} 0%</span>
|
||||
<span v-else>{{item.rate}}</span>
|
||||
<!-- <span v-if="item.value === 'enx'"> {{ $t(`course.timeLimited`) }} 0%</span> -->
|
||||
<span >{{item.rate}}</span>
|
||||
<span>{{item.mode}}</span>
|
||||
<span>{{item.quota}}</span>
|
||||
</li>
|
||||
|
||||
@@ -1228,6 +1228,8 @@ export default {
|
||||
this.getMinerAccountPowerData(this.PowerParams)
|
||||
this.getAccountPowerDistributionData(this.PowerDistribution)
|
||||
|
||||
|
||||
|
||||
},
|
||||
"$i18n.locale":(val)=>{
|
||||
location.reload();//刷新页面 刷新echarts
|
||||
@@ -1271,6 +1273,12 @@ export default {
|
||||
this.getAccountPowerDistributionData(this.PowerDistribution)
|
||||
|
||||
|
||||
this.registerRecoveryMethod('getMinerListData', this.MinerListParams);
|
||||
this.registerRecoveryMethod('getMinerAccountPowerData', this.PowerParams);
|
||||
this.registerRecoveryMethod('getAccountPowerDistributionData', this.PowerDistribution);
|
||||
this.registerRecoveryMethod('fetchPageInfo', {key:this.params.key});
|
||||
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -1320,7 +1328,7 @@ export default {
|
||||
},
|
||||
//返回权限 1矿工 2收益 3支付
|
||||
async fetchPageInfo(params){
|
||||
this.jurisdictionLoading = true
|
||||
this.setLoading('jurisdictionLoading', true);
|
||||
const data = await getPageInfo(params)
|
||||
console.log(data);
|
||||
if (data && data.code == 200) {
|
||||
@@ -1354,7 +1362,7 @@ export default {
|
||||
|
||||
}
|
||||
|
||||
this.jurisdictionLoading = false
|
||||
this.setLoading('jurisdictionLoading', false);
|
||||
},
|
||||
//获取当前挖矿账号信息(包含收益、余额)
|
||||
async getMinerAccountInfoData(params) {
|
||||
@@ -1362,11 +1370,11 @@ export default {
|
||||
this.MinerAccountData = data.data
|
||||
},
|
||||
async getMinerAccountPowerData(params) {
|
||||
this.powerChartLoading = true
|
||||
this.setLoading('powerChartLoading', true);
|
||||
const data = await getMinerAccountPower(params)
|
||||
|
||||
if (!data) {
|
||||
this.powerChartLoading = false
|
||||
this.setLoading('powerChartLoading', false);
|
||||
if (this.myChart) {
|
||||
this.myChart.dispose()//销毁图表实列
|
||||
}
|
||||
@@ -1399,13 +1407,13 @@ export default {
|
||||
this.option.series[1].data = rejectRate
|
||||
|
||||
this.inCharts()
|
||||
this.powerChartLoading = false
|
||||
this.setLoading('powerChartLoading', false);
|
||||
|
||||
|
||||
|
||||
},
|
||||
async getAccountPowerDistributionData(params) {
|
||||
this.barChartLoading = true
|
||||
this.setLoading('barChartLoading', true);
|
||||
const data = await getAccountPowerDistribution(params)
|
||||
let barData = data.data
|
||||
let xData = []
|
||||
@@ -1417,7 +1425,7 @@ export default {
|
||||
this.barOption.xAxis[0].data = xData
|
||||
this.barOption.series[0].data = barValueList
|
||||
this.barInCharts()
|
||||
this.barChartLoading = false
|
||||
this.setLoading('barChartLoading', false);
|
||||
},
|
||||
formatNumber(num) {//保留两位小数并补0
|
||||
const intPart = Math.floor(num);
|
||||
@@ -1425,7 +1433,7 @@ export default {
|
||||
return `${intPart}.${String(decimalPart).padStart(2, '0')}`;
|
||||
},
|
||||
async getMinerListData(params) {
|
||||
this.MinerListLoading = true
|
||||
this.setLoading('MinerListLoading', true);
|
||||
const data = await getMinerList(params)
|
||||
if (data && data.code == 200) {
|
||||
this.MinerListData = data.data
|
||||
@@ -1451,17 +1459,17 @@ export default {
|
||||
|
||||
}
|
||||
|
||||
this.MinerListLoading = false
|
||||
this.setLoading('MinerListLoading', false);
|
||||
|
||||
},
|
||||
|
||||
//小图
|
||||
async getMinerPowerData(params) {
|
||||
this.miniLoading=true
|
||||
this.setLoading('miniLoading', true);
|
||||
const data = await getMinerPower(params)
|
||||
|
||||
if (!data) {
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
return
|
||||
}
|
||||
let miniData = data.data
|
||||
@@ -1507,15 +1515,15 @@ export default {
|
||||
|
||||
|
||||
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
},
|
||||
//小图
|
||||
async getMinerPowerOnLine(params) {
|
||||
this.miniLoading=true
|
||||
this.setLoading('miniLoading', true);
|
||||
const data = await getMinerPower(params)
|
||||
|
||||
if (!data) {
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
return
|
||||
}
|
||||
let miniData = data.data
|
||||
@@ -1556,14 +1564,14 @@ export default {
|
||||
|
||||
|
||||
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
},
|
||||
//小图
|
||||
async getMinerPowerOffLine(params) {
|
||||
this.miniLoading=true
|
||||
this.setLoading('miniLoading', true);
|
||||
const data = await getMinerPower(params)
|
||||
if (!data) {
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
return
|
||||
}
|
||||
let miniData = data.data
|
||||
@@ -1605,7 +1613,7 @@ export default {
|
||||
|
||||
|
||||
|
||||
this.miniLoading=false
|
||||
this.setLoading('miniLoading', false);
|
||||
},
|
||||
async getHistoryIncomeData(params) {
|
||||
const data = await getHistoryIncome(params)
|
||||
|
||||
@@ -235,6 +235,10 @@ export default {
|
||||
|
||||
this.getLuckData(this.params)
|
||||
this.getBlockInfoData(this.BlockInfoParams)
|
||||
|
||||
this.registerRecoveryMethod('getLuckData', this.params);
|
||||
this.registerRecoveryMethod('getBlockInfoData', this.BlockInfoParams);
|
||||
|
||||
let value = localStorage.getItem("activeItemCoin")
|
||||
this.activeItemCoin = JSON.parse(value)
|
||||
this.currencyList = JSON.parse(localStorage.getItem("currencyList"))
|
||||
@@ -260,14 +264,14 @@ export default {
|
||||
// },
|
||||
|
||||
getLuckData: Debounce(async function (params) {
|
||||
this.LuckDataLoading = true
|
||||
this.setLoading('LuckDataLoading', true);
|
||||
const data = await getLuck(params)
|
||||
if (data && data.code == 200) {
|
||||
this.luckData = data.data
|
||||
}
|
||||
|
||||
|
||||
this.LuckDataLoading = false
|
||||
this.setLoading('LuckDataLoading', false);
|
||||
}, 200),
|
||||
// async getBlockInfoData(params) {
|
||||
// this.reportBlockLoading=true
|
||||
@@ -286,10 +290,10 @@ export default {
|
||||
// },
|
||||
getBlockInfoData: Debounce(async function (params) {
|
||||
|
||||
this.reportBlockLoading = true
|
||||
this.setLoading('reportBlockLoading', true);
|
||||
const data = await getBlockInfo(params)
|
||||
if (!data) {
|
||||
this.reportBlockLoading = false
|
||||
this.setLoading('reportBlockLoading', false);
|
||||
}
|
||||
this.totalSize = data.total
|
||||
this.BlockInfoData = data.rows
|
||||
@@ -298,7 +302,7 @@ export default {
|
||||
})
|
||||
// this.currentPage = 1
|
||||
// console.log(data,"获取币种信息");
|
||||
this.reportBlockLoading = false
|
||||
this.setLoading('reportBlockLoading', false);
|
||||
|
||||
}, 200),
|
||||
handleActiveItemChange(item) {
|
||||
@@ -314,6 +318,9 @@ export default {
|
||||
clickCurrency(item) {
|
||||
if (!item) return;
|
||||
// 设置标记,防止触发 watch
|
||||
|
||||
this.luckData={}
|
||||
|
||||
this.isInternalChange = true;
|
||||
this.activeItemCoin = item;
|
||||
this.$addStorageEvent(1, `activeItemCoin`, JSON.stringify(item))
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</el-menu>
|
||||
</div>
|
||||
|
||||
<div class="luckyBox" >
|
||||
<div class="luckyBox" v-show="this.activeItemCoin.value != 'enx' && this.activeItemCoin.value != 'alph'">
|
||||
|
||||
<div class="luckyItem">
|
||||
<span class="title">{{$t(`home.lucky3`)}}</span>
|
||||
@@ -125,7 +125,8 @@
|
||||
</el-col>
|
||||
<!-- v-loading = "LuckDataLoading" -->
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
|
||||
<div class="luckyBox" >
|
||||
|
||||
<div class="luckyBox" v-show="this.activeItemCoin.value != 'enx' && this.activeItemCoin.value != 'alph'" >
|
||||
|
||||
<div class="luckyItem">
|
||||
<span class="title">{{$t(`home.lucky3`)}}</span>
|
||||
|
||||
@@ -1,153 +1,397 @@
|
||||
<template>
|
||||
<div style="width: 1300px; height: 600px">
|
||||
<div id="chart" style="width: 100%; height: 100%; min-width: 500px"></div>
|
||||
<div>
|
||||
<h1>{{ msg }}</h1>
|
||||
|
||||
<!-- 用户ID输入部分 -->
|
||||
<div class="user-input-container">
|
||||
<div class="input-group" :class="{ 'disabled': isConnected }">
|
||||
<input
|
||||
v-model="email"
|
||||
placeholder="请输入您的用户邮箱"
|
||||
:disabled="isConnected"
|
||||
/>
|
||||
<input
|
||||
v-model="targetEmail"
|
||||
placeholder="请输入目标用户邮箱"
|
||||
:disabled="isConnected"
|
||||
@keyup.enter="!isConnected && !isConnecting && connectWebSocket()"
|
||||
/>
|
||||
</div>
|
||||
<div class="button-group">
|
||||
<button
|
||||
@click="connectWebSocket"
|
||||
:disabled="isConnected || isConnecting || !email || !targetEmail"
|
||||
:class="{ 'disabled': isConnected || isConnecting || !email || !targetEmail }"
|
||||
>
|
||||
{{ isConnecting ? '连接中...' : '连接' }}
|
||||
</button>
|
||||
<button
|
||||
v-if="isConnected"
|
||||
@click="disconnectWebSocket"
|
||||
class="disconnect-btn"
|
||||
>
|
||||
断开连接
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="connectionError" class="error-message">
|
||||
{{ connectionError }}
|
||||
</div>
|
||||
|
||||
<div v-if="isConnected">
|
||||
<!-- WebSocket 聊天部分 -->
|
||||
<div class="chat-container">
|
||||
<div class="message-list" ref="messageList">
|
||||
<div v-for="(msg, index) in receivedMessages" :key="index" class="message"
|
||||
:class="{ 'error-message': msg.error }">
|
||||
<div v-if="typeof msg === 'string'">{{ msg }}</div>
|
||||
<div v-else>
|
||||
<div class="message-header">
|
||||
<span class="message-sender">{{ msg.sender || 'Unknown' }}</span>
|
||||
<span class="message-time">{{ formatTime(msg.timestamp) }}</span>
|
||||
</div>
|
||||
<div class="message-content">{{ msg.content }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<textarea
|
||||
v-model="message"
|
||||
@keyup.enter="sendMessage"
|
||||
placeholder="输入消息..."
|
||||
rows="3"
|
||||
></textarea>
|
||||
<button @click="sendMessage" :disabled="!message.trim()">
|
||||
发送
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from "echarts";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
countDownTime: 60,
|
||||
timer: null,
|
||||
};
|
||||
},
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, nextTick, watch } from 'vue'
|
||||
import { Stomp } from '@stomp/stompjs'
|
||||
|
||||
mounted() {
|
||||
let base = +new Date(1968, 9, 3);
|
||||
let oneDay = 24 * 3600 * 1000;
|
||||
let date = [];
|
||||
let data = [Math.random() * 300];
|
||||
for (let i = 1; i < 20000; i++) {
|
||||
var now = new Date((base += oneDay));
|
||||
date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join("/"));
|
||||
data.push(Math.round((Math.random() - 0.5) * 20 + data[i - 1]));
|
||||
const props = defineProps({
|
||||
msg: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const message = ref('')
|
||||
const receivedMessages = ref([])
|
||||
const email = ref('')
|
||||
const targetEmail = ref('')
|
||||
const isConnected = ref(false)
|
||||
const isConnecting = ref(false)
|
||||
const connectionError = ref('')
|
||||
const messageList = ref(null)
|
||||
|
||||
// 创建一个响应式的 stompClient
|
||||
const stompClient = ref(null)
|
||||
|
||||
// 添加连接时间变量
|
||||
const connectTime = ref(null)
|
||||
|
||||
// 自动滚动到底部
|
||||
const scrollToBottom = async () => {
|
||||
await nextTick()
|
||||
if (messageList.value) {
|
||||
messageList.value.scrollTop = messageList.value.scrollHeight
|
||||
}
|
||||
}
|
||||
|
||||
// 监听消息列表变化,自动滚动
|
||||
watch(receivedMessages, () => {
|
||||
scrollToBottom()
|
||||
})
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = (timestamp) => {
|
||||
if (!timestamp) return ''
|
||||
try {
|
||||
const date = new Date(timestamp)
|
||||
return date.toLocaleTimeString()
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
// 连接WebSocket
|
||||
const connectWebSocket = () => {
|
||||
if (!email.value || !targetEmail.value) {
|
||||
connectionError.value = '请输入用户邮箱和目标用户邮箱'
|
||||
return
|
||||
}
|
||||
|
||||
connectionError.value = ''
|
||||
isConnecting.value = true
|
||||
connectTime.value = new Date() // 记录连接时间
|
||||
|
||||
try {
|
||||
stompClient.value = Stomp.client('ws://localhost:8101/chat/ws')
|
||||
stompClient.value.heartbeat.outgoing = 20000
|
||||
stompClient.value.heartbeat.incoming = 0
|
||||
|
||||
const connectHeaders = {
|
||||
'email': email.value,
|
||||
'type': 2 //0 游客 1 登录用户 2 客服
|
||||
}
|
||||
|
||||
// 添加 10 个空数据在前后
|
||||
for (let i = 0; i < 100; i++) {
|
||||
date.unshift(null);
|
||||
data.unshift(null);
|
||||
}
|
||||
for (let i = 0; i < 100; i++) {
|
||||
date.push(null);
|
||||
data.push(null);
|
||||
}
|
||||
stompClient.value.connect(
|
||||
connectHeaders,
|
||||
function(frame) {
|
||||
console.log('连接成功: ' + frame)
|
||||
console.log('连接时间:', connectTime.value?.toLocaleString())
|
||||
isConnected.value = true
|
||||
isConnecting.value = false
|
||||
|
||||
var option = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
position: function (pt) {
|
||||
return [pt[0], "10%"];
|
||||
},
|
||||
// 添加系统消息
|
||||
receivedMessages.value.push({
|
||||
sender: 'System',
|
||||
content: '已连接到聊天服务器',
|
||||
timestamp: new Date().toISOString(),
|
||||
system: true
|
||||
})
|
||||
|
||||
// 订阅自己管道的消息
|
||||
stompClient.value.subscribe(`/user/queue/${email.value}`, function(message) {
|
||||
console.log('收到消息:', message.body)
|
||||
try {
|
||||
const parsedMessage = JSON.parse(message.body)
|
||||
receivedMessages.value.push(parsedMessage)
|
||||
} catch (error) {
|
||||
console.error('消息解析失败:', error)
|
||||
receivedMessages.value.push({
|
||||
sender: 'System',
|
||||
content: `消息格式错误: ${message.body}`,
|
||||
timestamp: new Date().toISOString(),
|
||||
error: true
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
title: {
|
||||
left: "center",
|
||||
text: "Large Area Chart",
|
||||
},
|
||||
toolbox: {
|
||||
feature: {
|
||||
dataZoom: {
|
||||
yAxisIndex: "none",
|
||||
},
|
||||
restore: {},
|
||||
saveAsImage: {},
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
// boundaryGap: [0.5, 0.5],
|
||||
data: date,
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: "value",
|
||||
boundaryGap: [0, "100%"],
|
||||
axisLine: {
|
||||
show: true, // 显示 Y 轴线条
|
||||
},
|
||||
},
|
||||
{
|
||||
position: "right",
|
||||
type: "value",
|
||||
boundaryGap: [0, "100%"],
|
||||
},
|
||||
],
|
||||
dataZoom: [
|
||||
{
|
||||
type: "inside",
|
||||
start: 0,
|
||||
end: 10,
|
||||
},
|
||||
{
|
||||
start: 0,
|
||||
end: 10,
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: "Fake Data",
|
||||
type: "line",
|
||||
symbol: "none",
|
||||
sampling: "lttb",
|
||||
itemStyle: {
|
||||
color: "rgb(255, 70, 131)",
|
||||
},
|
||||
data: data,
|
||||
},
|
||||
],
|
||||
};
|
||||
this.myChart = echarts.init(document.getElementById("chart"));
|
||||
this.myChart.setOption(option);
|
||||
window.addEventListener(
|
||||
"resize", () => {
|
||||
if (this.myChart) this.myChart.resize();
|
||||
function(error) {
|
||||
console.error('连接失败:', error)
|
||||
isConnected.value = false
|
||||
isConnecting.value = false
|
||||
connectionError.value = `连接失败: ${error.headers?.message || error.message || '未知错误'}`
|
||||
}
|
||||
);
|
||||
},
|
||||
methods: {
|
||||
//初始化图表
|
||||
inCharts() {
|
||||
if (this.myChart == null) {
|
||||
this.myChart = echarts.init(document.getElementById("chart"));
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('初始化WebSocket客户端失败:', error)
|
||||
isConnected.value = false
|
||||
isConnecting.value = false
|
||||
connectionError.value = `初始化失败: ${error.message || '未知错误'}`
|
||||
}
|
||||
}
|
||||
|
||||
// 添加断开连接方法
|
||||
const disconnectWebSocket = () => {
|
||||
if (stompClient.value?.connected) {
|
||||
stompClient.value.disconnect(() => {
|
||||
const disconnectTime = new Date()
|
||||
const duration = connectTime.value ?
|
||||
Math.floor((disconnectTime.getTime() - connectTime.value.getTime()) / 1000) : 0
|
||||
|
||||
console.log('断开连接时间:', disconnectTime.toLocaleString())
|
||||
console.log(`连接持续时间: ${Math.floor(duration / 60)}分${duration % 60}秒`)
|
||||
|
||||
isConnected.value = false
|
||||
receivedMessages.value = []
|
||||
connectTime.value = null
|
||||
|
||||
// 添加提示
|
||||
connectionError.value = '已断开连接'
|
||||
setTimeout(() => {
|
||||
connectionError.value = ''
|
||||
}, 3000)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 发送消息方法
|
||||
const sendMessage = () => {
|
||||
if (!message.value.trim()) return
|
||||
|
||||
if (stompClient.value?.connected) {
|
||||
try {
|
||||
const messageObj = {
|
||||
email: targetEmail.value,
|
||||
content: message.value.trim()
|
||||
}
|
||||
|
||||
this.option.series[0].name = this.$t(`home.computingPower`);
|
||||
this.option.series[1].name = this.$t(`home.currencyPrice`);
|
||||
stompClient.value.send(
|
||||
`/point/send/message`,
|
||||
{},
|
||||
JSON.stringify(messageObj)
|
||||
)
|
||||
|
||||
this.myChart.setOption(this.option);
|
||||
// 回调函数,在渲染完成后执行
|
||||
this.myChart.on("finished", () => {
|
||||
// 在这里执行显示给用户的操作
|
||||
// console.log('图表渲染完成,显示给用户');
|
||||
this.minerChartLoading = false;
|
||||
});
|
||||
// window.addEventListener("resize", () => {
|
||||
// if (this.myChart) this.myChart.resize();
|
||||
// });
|
||||
// 添加自己发送的消息到显示列表
|
||||
receivedMessages.value.push({
|
||||
sender: email.value,
|
||||
content: message.value.trim(),
|
||||
timestamp: new Date().toISOString(),
|
||||
isSelf: true
|
||||
})
|
||||
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
throttle(() => {
|
||||
if (this.myChart) this.myChart.resize();
|
||||
}, 200)
|
||||
);
|
||||
},
|
||||
startCountDown() {
|
||||
this.timer = setInterval(() => {
|
||||
if (this.countDownTime <= 0) {
|
||||
//当监测到countDownTime为0时,清除计数器并且移除sessionStorage,然后执行提交试卷逻辑
|
||||
clearInterval(this.timer);
|
||||
sessionStorage.removeItem("exam_time");
|
||||
alert("提交试卷");
|
||||
} else if (this.countDownTime > 0) {
|
||||
//每秒让countDownTime -1秒,并设置到sessionStorage中
|
||||
this.countDownTime--;
|
||||
window.sessionStorage.setItem("exam_time", this.countDownTime);
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
},
|
||||
};
|
||||
message.value = ''
|
||||
} catch (error) {
|
||||
console.error('发送消息失败:', error)
|
||||
|
||||
receivedMessages.value.push({
|
||||
sender: 'System',
|
||||
content: `发送失败: ${error.message || '未知错误'}`,
|
||||
timestamp: new Date().toISOString(),
|
||||
error: true
|
||||
})
|
||||
}
|
||||
} else {
|
||||
connectionError.value = '连接已断开,请重新连接'
|
||||
isConnected.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 组件卸载时断开连接
|
||||
onUnmounted(() => {
|
||||
if (stompClient.value?.connected) {
|
||||
stompClient.value.disconnect()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.user-input-container {
|
||||
max-width: 400px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.chat-container {
|
||||
max-width: 600px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.message-list {
|
||||
height: 300px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #eee;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin: 8px 0;
|
||||
padding: 10px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
max-width: 80%;
|
||||
}
|
||||
|
||||
.message-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.8em;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.message-sender {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.message-time {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.message[class*="isSelf"] {
|
||||
background-color: #dcf8c6;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background-color: #ffebee;
|
||||
color: #d32f2f;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-family: inherit;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 8px 16px;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover:not(:disabled) {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.disconnect-btn {
|
||||
background-color: #dc3545;
|
||||
}
|
||||
|
||||
.disconnect-btn:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
|
||||
input:disabled, textarea:disabled {
|
||||
background-color: #f5f5f5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
</style>
|
||||
@@ -105,9 +105,9 @@ export default {
|
||||
console.log(res,"文件返回");
|
||||
|
||||
this.ruleForm.files = res.data.data.id
|
||||
if (this.ruleForm.files) {//成功拿到返回ID
|
||||
this.fetchSubmitWork(this.ruleForm)
|
||||
}
|
||||
// if (this.ruleForm.files) {//成功拿到返回ID
|
||||
// this.fetchSubmitWork(this.ruleForm)
|
||||
// }
|
||||
})
|
||||
} else {
|
||||
|
||||
|
||||
@@ -167,6 +167,7 @@ export default {
|
||||
this.workOrderId = localStorage.getItem("workOrderId")
|
||||
if (this.workOrderId) {
|
||||
this.fetchTicketDetails({ id: this.workOrderId })
|
||||
this.registerRecoveryMethod('fetchTicketDetails', { id: this.workOrderId });
|
||||
}
|
||||
|
||||
// this.faultList = JSON.parse(localStorage.getItem('faultList') )
|
||||
|
||||
@@ -198,18 +198,22 @@ export default {
|
||||
case `all`:
|
||||
this.params.status = 0
|
||||
this.fetchRechargeRecord0(this.params)
|
||||
this.registerRecoveryMethod('fetchRechargeRecord0', this.params);
|
||||
break;
|
||||
case `pending`:
|
||||
this.params.status = 2
|
||||
this.fetchRechargeRecord2(this.params)
|
||||
this.registerRecoveryMethod('fetchRechargeRecord2', this.params);
|
||||
break;
|
||||
case `Finished`:
|
||||
this.params.status = 10
|
||||
this.fetchRechargeRecord10(this.params)
|
||||
this.registerRecoveryMethod('fetchRechargeRecord10', this.params);
|
||||
break;
|
||||
case `pendingProcessing`:
|
||||
this.params.status = 1
|
||||
this.fetchRechargeRecord1(this.params)
|
||||
this.registerRecoveryMethod('fetchRechargeRecord1', this.params);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -95,14 +95,17 @@ export default {
|
||||
case "pending":
|
||||
this.params.status = 1
|
||||
this.fetchPrivateConsume1(this.params)
|
||||
this.registerRecoveryMethod('fetchPrivateConsume1', this.params);
|
||||
break;
|
||||
case "success"://已完成工单
|
||||
this.params.status = 2
|
||||
this.fetchPrivateConsume2(this.params)
|
||||
this.registerRecoveryMethod('fetchPrivateConsume2', this.params);
|
||||
break;
|
||||
case "reply"://全部工单
|
||||
this.params.status = 0
|
||||
this.fetchPrivateConsume0(this.params)
|
||||
this.registerRecoveryMethod('fetchPrivateConsume0', this.params);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
Binary file not shown.
1
mining-pool/test/css/app-113c6c50.6cbc2492.css
Normal file
1
mining-pool/test/css/app-113c6c50.6cbc2492.css
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/css/app-113c6c50.6cbc2492.css.gz
Normal file
BIN
mining-pool/test/css/app-113c6c50.6cbc2492.css.gz
Normal file
Binary file not shown.
1
mining-pool/test/css/app-113c6c50.af06316f.css
Normal file
1
mining-pool/test/css/app-113c6c50.af06316f.css
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/css/app-113c6c50.af06316f.css.gz
Normal file
BIN
mining-pool/test/css/app-113c6c50.af06316f.css.gz
Normal file
Binary file not shown.
1
mining-pool/test/css/app-42f9d7e6.23095695.css
Normal file
1
mining-pool/test/css/app-42f9d7e6.23095695.css
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/css/app-42f9d7e6.23095695.css.gz
Normal file
BIN
mining-pool/test/css/app-42f9d7e6.23095695.css.gz
Normal file
Binary file not shown.
1
mining-pool/test/css/app-72600b29.4fd214e9.css
Normal file
1
mining-pool/test/css/app-72600b29.4fd214e9.css
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/css/app-72600b29.4fd214e9.css.gz
Normal file
BIN
mining-pool/test/css/app-72600b29.4fd214e9.css.gz
Normal file
Binary file not shown.
1
mining-pool/test/css/app-72600b29.83c22f01.css
Normal file
1
mining-pool/test/css/app-72600b29.83c22f01.css
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/css/app-72600b29.83c22f01.css.gz
Normal file
BIN
mining-pool/test/css/app-72600b29.83c22f01.css.gz
Normal file
Binary file not shown.
1
mining-pool/test/css/app-b4c4f6ec.c96edfc1.css
Normal file
1
mining-pool/test/css/app-b4c4f6ec.c96edfc1.css
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/css/app-b4c4f6ec.c96edfc1.css.gz
Normal file
BIN
mining-pool/test/css/app-b4c4f6ec.c96edfc1.css.gz
Normal file
Binary file not shown.
1
mining-pool/test/css/app-b4c4f6ec.fbcc1022.css
Normal file
1
mining-pool/test/css/app-b4c4f6ec.fbcc1022.css
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/css/app-b4c4f6ec.fbcc1022.css.gz
Normal file
BIN
mining-pool/test/css/app-b4c4f6ec.fbcc1022.css.gz
Normal file
Binary file not shown.
1
mining-pool/test/css/app-f035d474.0e6b8898.css
Normal file
1
mining-pool/test/css/app-f035d474.0e6b8898.css
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/css/app-f035d474.0e6b8898.css.gz
Normal file
BIN
mining-pool/test/css/app-f035d474.0e6b8898.css.gz
Normal file
Binary file not shown.
BIN
mining-pool/test/img/home.2a3cb050.png
Normal file
BIN
mining-pool/test/img/home.2a3cb050.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 716 KiB |
BIN
mining-pool/test/img/home.4c2d8f62.png
Normal file
BIN
mining-pool/test/img/home.4c2d8f62.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
@@ -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_irzdjxdsrq8.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.d4a64849.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.454dc86a.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.b52260c2.js></script><script defer src=/js/app-6f02571b.3a5059dd.js></script><script defer src=/js/app-01dc9ae1.188fe4f5.js></script><script defer src=/js/app-b4c4f6ec.d94757ae.js></script><script defer src=/js/app-72600b29.4950ef3f.js></script><script defer src=/js/app-f035d474.f2154b52.js></script><script defer src=/js/app-113c6c50.8a204225.js></script><link href=/css/chunk-vendors-5c533fba.6f97509c.css rel=stylesheet><link href=/css/app-42f9d7e6.afc6aa48.css rel=stylesheet><link href=/css/app-01dc9ae1.825b7ca3.css rel=stylesheet><link href=/css/app-b4c4f6ec.a41cc6d7.css rel=stylesheet><link href=/css/app-72600b29.adc64aa5.css rel=stylesheet><link href=/css/app-f035d474.1006091b.css rel=stylesheet><link href=/css/app-113c6c50.0c83a15a.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_irzdjxdsrq8.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.17cb0808.js></script><script defer src=/js/app-5c551db8.2b99b68c.js></script><script defer src=/js/app-01dc9ae1.188fe4f5.js></script><script defer src=/js/app-b4c4f6ec.bf0536f4.js></script><script defer src=/js/app-72600b29.6b68c3d1.js></script><script defer src=/js/app-f035d474.30e8939b.js></script><script defer src=/js/app-113c6c50.28d27f0c.js></script><link href=/css/chunk-vendors-5c533fba.6f97509c.css rel=stylesheet><link href=/css/app-42f9d7e6.23095695.css rel=stylesheet><link href=/css/app-01dc9ae1.825b7ca3.css rel=stylesheet><link href=/css/app-b4c4f6ec.c96edfc1.css rel=stylesheet><link href=/css/app-72600b29.83c22f01.css rel=stylesheet><link href=/css/app-f035d474.0e6b8898.css rel=stylesheet><link href=/css/app-113c6c50.af06316f.css rel=stylesheet></head><body><div id=app></div></body></html>
|
||||
1
mining-pool/test/js/app-113c6c50.28d27f0c.js
Normal file
1
mining-pool/test/js/app-113c6c50.28d27f0c.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-113c6c50.28d27f0c.js.gz
Normal file
BIN
mining-pool/test/js/app-113c6c50.28d27f0c.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-113c6c50.96c3bebd.js
Normal file
1
mining-pool/test/js/app-113c6c50.96c3bebd.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-113c6c50.96c3bebd.js.gz
Normal file
BIN
mining-pool/test/js/app-113c6c50.96c3bebd.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-42f9d7e6.17cb0808.js
Normal file
1
mining-pool/test/js/app-42f9d7e6.17cb0808.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-42f9d7e6.17cb0808.js.gz
Normal file
BIN
mining-pool/test/js/app-42f9d7e6.17cb0808.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-42f9d7e6.b12571df.js
Normal file
1
mining-pool/test/js/app-42f9d7e6.b12571df.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-42f9d7e6.b12571df.js.gz
Normal file
BIN
mining-pool/test/js/app-42f9d7e6.b12571df.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-5c551db8.2b99b68c.js
Normal file
1
mining-pool/test/js/app-5c551db8.2b99b68c.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-5c551db8.2b99b68c.js.gz
Normal file
BIN
mining-pool/test/js/app-5c551db8.2b99b68c.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-5c551db8.4db2eb93.js
Normal file
1
mining-pool/test/js/app-5c551db8.4db2eb93.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-5c551db8.4db2eb93.js.gz
Normal file
BIN
mining-pool/test/js/app-5c551db8.4db2eb93.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-72600b29.5a5f9303.js
Normal file
1
mining-pool/test/js/app-72600b29.5a5f9303.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-72600b29.5a5f9303.js.gz
Normal file
BIN
mining-pool/test/js/app-72600b29.5a5f9303.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-72600b29.6b68c3d1.js
Normal file
1
mining-pool/test/js/app-72600b29.6b68c3d1.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-72600b29.6b68c3d1.js.gz
Normal file
BIN
mining-pool/test/js/app-72600b29.6b68c3d1.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-b4c4f6ec.025712d3.js
Normal file
1
mining-pool/test/js/app-b4c4f6ec.025712d3.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-b4c4f6ec.025712d3.js.gz
Normal file
BIN
mining-pool/test/js/app-b4c4f6ec.025712d3.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-b4c4f6ec.bf0536f4.js
Normal file
1
mining-pool/test/js/app-b4c4f6ec.bf0536f4.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-b4c4f6ec.bf0536f4.js.gz
Normal file
BIN
mining-pool/test/js/app-b4c4f6ec.bf0536f4.js.gz
Normal file
Binary file not shown.
1
mining-pool/test/js/app-f035d474.30e8939b.js
Normal file
1
mining-pool/test/js/app-f035d474.30e8939b.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/app-f035d474.30e8939b.js.gz
Normal file
BIN
mining-pool/test/js/app-f035d474.30e8939b.js.gz
Normal file
Binary file not shown.
18
mining-pool/test/js/chunk-vendors-377fed06.159de137.js
Normal file
18
mining-pool/test/js/chunk-vendors-377fed06.159de137.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/chunk-vendors-377fed06.159de137.js.gz
Normal file
BIN
mining-pool/test/js/chunk-vendors-377fed06.159de137.js.gz
Normal file
Binary file not shown.
16
mining-pool/test/js/chunk-vendors-89d5c698.2190b4ca.js
Normal file
16
mining-pool/test/js/chunk-vendors-89d5c698.2190b4ca.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/chunk-vendors-89d5c698.2190b4ca.js.gz
Normal file
BIN
mining-pool/test/js/chunk-vendors-89d5c698.2190b4ca.js.gz
Normal file
Binary file not shown.
3
mining-pool/test/js/chunk-vendors-945ce2fe.648a91a9.js
Normal file
3
mining-pool/test/js/chunk-vendors-945ce2fe.648a91a9.js
Normal file
File diff suppressed because one or more lines are too long
BIN
mining-pool/test/js/chunk-vendors-945ce2fe.648a91a9.js.gz
Normal file
BIN
mining-pool/test/js/chunk-vendors-945ce2fe.648a91a9.js.gz
Normal file
Binary file not shown.
@@ -3,7 +3,10 @@ Allow: / #允许爬取根目录下的所有内
|
||||
Disallow: /admin
|
||||
Disallow: /oapi #禁止爬取oapi和api开头的接口内容
|
||||
Disallow: /api
|
||||
Disallow: /*/AccessMiningPool/enx
|
||||
# 明确禁止访问不存在的路径 $精确匹配
|
||||
Disallow: /*/AccessMiningPool/enx$
|
||||
Disallow: /en/AccessMiningPool/enx$
|
||||
Disallow: /zh/AccessMiningPool/enx$
|
||||
|
||||
|
||||
# 站点地图配置
|
||||
|
||||
@@ -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-04-09T07:15:58.590Z</lastmod><changefreq>daily</changefreq><priority>1.0</priority></url><url><loc>https://m2pool.com/en/dataDisplay</loc><lastmod>2025-04-09T07:15:58.590Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://m2pool.com/en/ServiceTerms</loc><lastmod>2025-04-09T07:15:58.590Z</lastmod><changefreq>monthly</changefreq><priority>0.6</priority></url><url><loc>https://m2pool.com/en/apiFile</loc><lastmod>2025-04-09T07:15:58.590Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/rate</loc><lastmod>2025-04-09T07:15:58.590Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/nexaAccess</loc><lastmod>2025-04-09T07:15:58.590Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/grsAccess</loc><lastmod>2025-04-09T07:15:58.590Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/monaAccess</loc><lastmod>2025-04-09T07:15:58.590Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgbsAccess</loc><lastmod>2025-04-09T07:15:58.590Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgbqAccess</loc><lastmod>2025-04-09T07:15:58.590Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgboAccess</loc><lastmod>2025-04-09T07:15:58.590Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/rxdAccess</loc><lastmod>2025-04-09T07:15:58.590Z</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-04-22T06:17:28.553Z</lastmod><changefreq>daily</changefreq><priority>1.0</priority></url><url><loc>https://m2pool.com/en/dataDisplay</loc><lastmod>2025-04-22T06:17:28.553Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://m2pool.com/en/ServiceTerms</loc><lastmod>2025-04-22T06:17:28.553Z</lastmod><changefreq>monthly</changefreq><priority>0.6</priority></url><url><loc>https://m2pool.com/en/apiFile</loc><lastmod>2025-04-22T06:17:28.553Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/rate</loc><lastmod>2025-04-22T06:17:28.553Z</lastmod><changefreq>weekly</changefreq><priority>0.8</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/nexaAccess</loc><lastmod>2025-04-22T06:17:28.553Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/grsAccess</loc><lastmod>2025-04-22T06:17:28.553Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/monaAccess</loc><lastmod>2025-04-22T06:17:28.553Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgbsAccess</loc><lastmod>2025-04-22T06:17:28.553Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgbqAccess</loc><lastmod>2025-04-22T06:17:28.553Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/dgboAccess</loc><lastmod>2025-04-22T06:17:28.553Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/en/AccessMiningPool/rxdAccess</loc><lastmod>2025-04-22T06:17:28.553Z</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-04-09T07:15:58.582Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/dataDisplay</loc><lastmod>2025-04-09T07:15:58.582Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/ServiceTerms</loc><lastmod>2025-04-09T07:15:58.582Z</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/apiFile</loc><lastmod>2025-04-09T07:15:58.582Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/rate</loc><lastmod>2025-04-09T07:15:58.582Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/nexaAccess</loc><lastmod>2025-04-09T07:15:58.582Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/grsAccess</loc><lastmod>2025-04-09T07:15:58.582Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/monaAccess</loc><lastmod>2025-04-09T07:15:58.582Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgbsAccess</loc><lastmod>2025-04-09T07:15:58.582Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgbqAccess</loc><lastmod>2025-04-09T07:15:58.582Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgboAccess</loc><lastmod>2025-04-09T07:15:58.582Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/rxdAccess</loc><lastmod>2025-04-09T07:15:58.582Z</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-04-22T06:17:28.543Z</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/dataDisplay</loc><lastmod>2025-04-22T06:17:28.543Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/ServiceTerms</loc><lastmod>2025-04-22T06:17:28.543Z</lastmod><changefreq>monthly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/apiFile</loc><lastmod>2025-04-22T06:17:28.543Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/rate</loc><lastmod>2025-04-22T06:17:28.543Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/nexaAccess</loc><lastmod>2025-04-22T06:17:28.543Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/grsAccess</loc><lastmod>2025-04-22T06:17:28.543Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/monaAccess</loc><lastmod>2025-04-22T06:17:28.543Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgbsAccess</loc><lastmod>2025-04-22T06:17:28.543Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgbqAccess</loc><lastmod>2025-04-22T06:17:28.543Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/dgboAccess</loc><lastmod>2025-04-22T06:17:28.543Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url><url><loc>https://m2pool.com/zh/AccessMiningPool/rxdAccess</loc><lastmod>2025-04-22T06:17:28.543Z</lastmod><changefreq>weekly</changefreq><priority>0.7</priority></url></urlset>
|
||||
Binary file not shown.
Reference in New Issue
Block a user