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>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<router-view class="page" />
|
<router-view class="page" />
|
||||||
|
<!-- <ChatWidget /> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script >
|
<script >
|
||||||
|
import ChatWidget from '../src/components/ChatWidget.vue';
|
||||||
import { Debounce, throttle } from '@/utils/publicMethods';
|
import { Debounce, throttle } from '@/utils/publicMethods';
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
ChatWidget
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
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 {alerts_zh,alerts_en} from'./alerts'
|
||||||
import {seo_zh,seo_en} from'./seo'
|
import {seo_zh,seo_en} from'./seo'
|
||||||
import {chooseUs_zh,chooseUs_en} from'./dataDisplay'
|
import {chooseUs_zh,chooseUs_en} from'./dataDisplay'
|
||||||
|
import {ChatWidget_zh,ChatWidget_en} from'./ChatWidget'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ export default {
|
|||||||
...alerts_zh,
|
...alerts_zh,
|
||||||
...seo_zh,
|
...seo_zh,
|
||||||
...chooseUs_zh,
|
...chooseUs_zh,
|
||||||
|
...ChatWidget_zh,
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -50,7 +51,7 @@ export default {
|
|||||||
...alerts_en,
|
...alerts_en,
|
||||||
...seo_en,
|
...seo_en,
|
||||||
...chooseUs_en,
|
...chooseUs_en,
|
||||||
|
...ChatWidget_en,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ import './assets/icons/iconfont/iconfont.css'
|
|||||||
import {$addStorageEvent} from '../src/utils/publicMethods'
|
import {$addStorageEvent} from '../src/utils/publicMethods'
|
||||||
import MetaInfo from 'vue-meta-info'
|
import MetaInfo from 'vue-meta-info'
|
||||||
import loadingStateMixin from './utils/loadingStateMixin';
|
import loadingStateMixin from './utils/loadingStateMixin';
|
||||||
|
import networkRecoveryMixin from './mixins/networkRecoveryMixin';
|
||||||
|
import './utils/loadingRecovery';
|
||||||
|
import errorNotificationManager from '../src/utils/errorNotificationManager';
|
||||||
|
|
||||||
Vue.use(MetaInfo)
|
Vue.use(MetaInfo)
|
||||||
Vue.prototype.$addStorageEvent = $addStorageEvent // 添加storage事件
|
Vue.prototype.$addStorageEvent = $addStorageEvent // 添加storage事件
|
||||||
@@ -21,7 +24,9 @@ Vue.use(ElementUI, {
|
|||||||
Vue.prototype.$axios = axios
|
Vue.prototype.$axios = axios
|
||||||
|
|
||||||
console.log = ()=>{} //全局关闭打印
|
console.log = ()=>{} //全局关闭打印
|
||||||
|
// 全局注册混入
|
||||||
Vue.mixin(loadingStateMixin);
|
Vue.mixin(loadingStateMixin);
|
||||||
|
Vue.mixin(networkRecoveryMixin);
|
||||||
|
|
||||||
Vue.prototype.$baseApi = process.env.VUE_APP_BASE_URL //图片base路径
|
Vue.prototype.$baseApi = process.env.VUE_APP_BASE_URL //图片base路径
|
||||||
const screenWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
const screenWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
|
||||||
@@ -45,6 +50,11 @@ router.beforeEach((to, from, next) => {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 定期清理过期的错误记录
|
||||||
|
setInterval(() => {
|
||||||
|
errorNotificationManager.cleanup();
|
||||||
|
}, 60000); // 每分钟清理一次
|
||||||
|
|
||||||
window.vm = new Vue({
|
window.vm = new Vue({
|
||||||
router,
|
router,
|
||||||
store,
|
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',
|
path: '/:lang/AccessMiningPool',
|
||||||
name: '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 errorCode from './errorCode'
|
||||||
import { Notification, MessageBox, Message } from 'element-ui'
|
import { Notification, MessageBox, Message } from 'element-ui'
|
||||||
import loadingManager from './loadingManager';
|
import loadingManager from './loadingManager';
|
||||||
|
import errorNotificationManager from './errorNotificationManager';
|
||||||
|
|
||||||
// 创建axios实例
|
// 创建axios实例
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||||
@@ -19,10 +21,51 @@ let lastNetworkErrorTime = 0; // 上次网络错误提示时间
|
|||||||
let pendingRequests = new Map();
|
let pendingRequests = new Map();
|
||||||
|
|
||||||
|
|
||||||
|
// 网络状态监听器
|
||||||
|
// 网络状态最后提示时间
|
||||||
|
let lastNetworkStatusTime = {
|
||||||
|
online: 0,
|
||||||
|
offline: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建一个全局标志,确保每次网络恢复只显示一次提示
|
||||||
|
let networkRecoveryInProgress = false;
|
||||||
|
|
||||||
// 网络状态监听器
|
// 网络状态监听器
|
||||||
window.addEventListener('online', () => {
|
window.addEventListener('online', () => {
|
||||||
// 网络恢复时,重试所有待处理的请求
|
|
||||||
const now = Date.now();
|
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 = [];
|
const pendingPromises = [];
|
||||||
|
|
||||||
pendingRequests.forEach(async (request, key) => {
|
pendingRequests.forEach(async (request, key) => {
|
||||||
@@ -71,34 +114,56 @@ window.addEventListener('online', () => {
|
|||||||
// 等待所有请求完成
|
// 等待所有请求完成
|
||||||
Promise.allSettled(pendingPromises).then(() => {
|
Promise.allSettled(pendingPromises).then(() => {
|
||||||
// 重置所有 loading 状态
|
// 重置所有 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'));
|
window.dispatchEvent(new CustomEvent('network-retry-complete'));
|
||||||
});
|
|
||||||
|
|
||||||
// 显示网络恢复提示
|
// 重置网络恢复标志
|
||||||
if (window.vm && window.vm.$message) {
|
setTimeout(() => {
|
||||||
window.vm.$message({
|
networkRecoveryInProgress = false;
|
||||||
message: window.vm.$i18n.t('home.networkReconnected') || '网络已重新连接,正在恢复数据...',
|
}, 5000); // 5秒后允许再次处理网络恢复
|
||||||
type: 'success',
|
});
|
||||||
duration: 3000
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 使用错误提示管理器控制网络断开提示
|
||||||
window.addEventListener('offline', () => {
|
window.addEventListener('offline', () => {
|
||||||
if (window.vm && window.vm.$message) {
|
if (window.vm && window.vm.$message && errorNotificationManager.canShowError('networkOffline')) {
|
||||||
window.vm.$message({
|
window.vm.$message({
|
||||||
message: window.vm.$i18n.t('home.networkOffline') || '网络连接已断开,系统将在恢复连接后自动重试',
|
message: window.vm.$i18n.t('home.networkOffline') || '网络连接已断开,系统将在恢复连接后自动重试',
|
||||||
type: 'warning',
|
type: 'error',
|
||||||
duration: 3000
|
duration: 5000,
|
||||||
|
showClose: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
service.defaults.retry = 2;// 重试次数
|
service.defaults.retry = 2;// 重试次数
|
||||||
service.defaults.retryDelay = 2000;
|
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', "")
|
localStorage.setItem('superReportError', "")
|
||||||
let superReportError = localStorage.getItem('superReportError')
|
let superReportError = localStorage.getItem('superReportError')
|
||||||
@@ -224,7 +289,6 @@ service.interceptors.response.use(res => {
|
|||||||
|
|
||||||
|
|
||||||
let { message } = error;
|
let { message } = error;
|
||||||
|
|
||||||
if (message == "Network Error" || message.includes("timeout")) {
|
if (message == "Network Error" || message.includes("timeout")) {
|
||||||
if (!navigator.onLine) {
|
if (!navigator.onLine) {
|
||||||
// 断网状态,添加到重试队列
|
// 断网状态,添加到重试队列
|
||||||
@@ -262,30 +326,37 @@ service.interceptors.response.use(res => {
|
|||||||
|
|
||||||
console.log('请求已加入断网重连队列:', error.config.url);
|
console.log('请求已加入断网重连队列:', error.config.url);
|
||||||
}
|
}
|
||||||
} else if ((error.config.retry > 0 && error.config)) {
|
} else {
|
||||||
// 保留现有的重试逻辑
|
// 网络已连接,但请求失败,尝试重试
|
||||||
error.config.retry--;
|
// 确保 config 中有 __retryCount 字段
|
||||||
return new Promise(resolve => {
|
error.config.__retryCount = error.config.__retryCount || 0;
|
||||||
setTimeout(() => {
|
|
||||||
resolve(service(error.config));
|
// 判断是否可以重试
|
||||||
}, 2000);
|
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) {
|
if (!superReportError) {
|
||||||
superReportError = "error"
|
superReportError = "error"
|
||||||
localStorage.setItem('superReportError', superReportError)
|
localStorage.setItem('superReportError', superReportError)
|
||||||
let { message } = error;
|
//使用错误提示管理器errorNotificationManager
|
||||||
if (message == "Network Error") {
|
if (errorNotificationManager.canShowError(message)) {
|
||||||
// message = "后端接口网络连接异常,请刷新重试";
|
if (message == "Network Error") {
|
||||||
const now = Date.now();
|
|
||||||
if (now - lastNetworkErrorTime > NETWORK_ERROR_THROTTLE_TIME) {
|
|
||||||
lastNetworkErrorTime = now; // 更新最后提示时间
|
|
||||||
Message({
|
Message({
|
||||||
message: window.vm.$i18n.t(`home.NetworkError`),
|
message: window.vm.$i18n.t(`home.NetworkError`),
|
||||||
type: 'error',
|
type: 'error',
|
||||||
@@ -293,42 +364,38 @@ service.interceptors.response.use(res => {
|
|||||||
showClose: true
|
showClose: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else if (message.includes("timeout")) {
|
||||||
}
|
Message({
|
||||||
else if (message.includes("timeout")) {
|
message: window.vm.$i18n.t(`home.requestTimeout`),
|
||||||
// message = "系统接口请求超时,请刷新重试";
|
type: 'error',
|
||||||
Message({
|
duration: 5 * 1000,
|
||||||
message: window.vm.$i18n.t(`home.requestTimeout`),
|
showClose: true
|
||||||
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',
|
||||||
else if (message.includes("Request failed with status code")) {
|
duration: 5 * 1000,
|
||||||
// message = "系统接口" + message.substr(message.length - 3) + "异常";
|
showClose: true
|
||||||
Message({
|
});
|
||||||
message: "系统接口" + message.substr(message.length - 3) + "异常",
|
} else {
|
||||||
type: 'error',
|
Message({
|
||||||
duration: 5 * 1000,
|
message: message,
|
||||||
showClose: true
|
type: 'error',
|
||||||
})
|
duration: 5 * 1000,
|
||||||
|
showClose: true
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// 避免完全不提示,可以在控制台记录被抑制的错误
|
||||||
Message({
|
console.log('[错误提示] 已抑制重复错误:', message);
|
||||||
message: message,
|
|
||||||
type: 'error',
|
|
||||||
duration: 5 * 1000,
|
|
||||||
showClose: true
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return Promise.reject(error)
|
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.stateList = JSON.parse(localStorage.getItem('stateList') )
|
||||||
// this.typeList = JSON.parse(localStorage.getItem('typeList') )
|
// this.typeList = JSON.parse(localStorage.getItem('typeList') )
|
||||||
|
|
||||||
|
this.registerRecoveryMethod('fetchTicketDetails', { id: this.workOrderId });
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchBKendTicket(params){
|
async fetchBKendTicket(params){
|
||||||
this.totalDetailsLoading =true
|
// this.totalDetailsLoading =true
|
||||||
|
this.setLoading('totalDetailsLoading', true);
|
||||||
const data = await getBKendTicket(params)
|
const data = await getBKendTicket(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -185,11 +188,12 @@ export default {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.totalDetailsLoading =false
|
this.setLoading('totalDetailsLoading', false);
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetchReply(params){
|
async fetchReply(params){
|
||||||
this.totalDetailsLoading = true
|
// this.totalDetailsLoading = true
|
||||||
|
this.setLoading('totalDetailsLoading', true);
|
||||||
const data = await getReply(params)
|
const data = await getReply(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -205,7 +209,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.totalDetailsLoading = false
|
this.setLoading('totalDetailsLoading', false);
|
||||||
},
|
},
|
||||||
handelType2(label){
|
handelType2(label){
|
||||||
if (label) {
|
if (label) {
|
||||||
@@ -231,14 +235,15 @@ export default {
|
|||||||
},
|
},
|
||||||
//请求工单详情
|
//请求工单详情
|
||||||
async fetchTicketDetails(param) {
|
async fetchTicketDetails(param) {
|
||||||
this.totalDetailsLoading = true
|
// this.totalDetailsLoading = true
|
||||||
|
this.setLoading('totalDetailsLoading', true);
|
||||||
const { data } = await getDetails(param)
|
const { data } = await getDetails(param)
|
||||||
|
|
||||||
this.recordList = data.list
|
this.recordList = data.list
|
||||||
this.ticketDetails = data
|
this.ticketDetails = data
|
||||||
|
|
||||||
|
|
||||||
this.totalDetailsLoading = false
|
this.setLoading('totalDetailsLoading', false);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export default {
|
|||||||
this.params.maId = this.receiveData.id
|
this.params.maId = this.receiveData.id
|
||||||
}
|
}
|
||||||
this.fetchList(this.listParams)
|
this.fetchList(this.listParams)
|
||||||
|
this.registerRecoveryMethod('fetchList', this.listParams);
|
||||||
|
|
||||||
},
|
},
|
||||||
methods:{
|
methods:{
|
||||||
@@ -100,7 +100,8 @@ export default {
|
|||||||
return getImageUrl(path);
|
return getImageUrl(path);
|
||||||
},
|
},
|
||||||
async fetchAddNoticeEmail(params){
|
async fetchAddNoticeEmail(params){
|
||||||
this.addMinerLoading = true
|
// this.addMinerLoading = true
|
||||||
|
this.setLoading('addMinerLoading', true);
|
||||||
const data = await getAddNoticeEmail(params)
|
const data = await getAddNoticeEmail(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -121,17 +122,18 @@ export default {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.addMinerLoading = false
|
this.setLoading('addMinerLoading', false);
|
||||||
|
|
||||||
},
|
},
|
||||||
async fetchList(params){
|
async fetchList(params){
|
||||||
this.alertsLoading=true
|
// this.alertsLoading=true
|
||||||
|
this.setLoading('alertsLoading', true);
|
||||||
const data = await getList(params)
|
const data = await getList(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.tableData = data.rows
|
this.tableData = data.rows
|
||||||
|
|
||||||
}
|
}
|
||||||
this.alertsLoading=false
|
this.setLoading('alertsLoading', false);
|
||||||
|
|
||||||
},
|
},
|
||||||
async fetchCode(params){
|
async fetchCode(params){
|
||||||
@@ -147,7 +149,8 @@ export default {
|
|||||||
|
|
||||||
},
|
},
|
||||||
async fetchUpdateInfo(params){
|
async fetchUpdateInfo(params){
|
||||||
this.addMinerLoading = true
|
// this.addMinerLoading = true
|
||||||
|
this.setLoading('addMinerLoading', true);
|
||||||
const data = await getUpdateInfo(params)
|
const data = await getUpdateInfo(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -159,11 +162,12 @@ export default {
|
|||||||
this.fetchList(this.listParams)
|
this.fetchList(this.listParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addMinerLoading = false
|
this.setLoading('addMinerLoading', false);
|
||||||
|
|
||||||
},
|
},
|
||||||
async fetchDeleteEmail(params){
|
async fetchDeleteEmail(params){
|
||||||
this.deleteLoading = true
|
// this.deleteLoading = true
|
||||||
|
this.setLoading('deleteLoading', true);
|
||||||
const data = await deleteEmail(params)
|
const data = await deleteEmail(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -175,7 +179,7 @@ export default {
|
|||||||
this.fetchList(this.listParams)
|
this.fetchList(this.listParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.deleteLoading = false
|
this.setLoading('deleteLoading', false);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -442,7 +442,7 @@
|
|||||||
<!-- 挖矿账号下矿工总览 -->
|
<!-- 挖矿账号下矿工总览 -->
|
||||||
<div class="Pool">
|
<div class="Pool">
|
||||||
<p class="hash">{{ $t(`apiFile.overviewOfMiners`) }}</p>
|
<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.jurisdiction`) }} account</p>
|
||||||
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
||||||
<table border="1">
|
<table border="1">
|
||||||
@@ -797,7 +797,7 @@
|
|||||||
<!-- 指定矿机历史24h平均算力 -->
|
<!-- 指定矿机历史24h平均算力 -->
|
||||||
<div class="Pool">
|
<div class="Pool">
|
||||||
<p class="hash">{{ $t(`apiFile.miningMachineHistory24h`) }}</p>
|
<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.jurisdiction`) }} miner</p>
|
||||||
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
||||||
<table border="1">
|
<table border="1">
|
||||||
@@ -1371,7 +1371,7 @@
|
|||||||
<!-- 挖矿账号下矿工总览 -->
|
<!-- 挖矿账号下矿工总览 -->
|
||||||
<div class="Pool">
|
<div class="Pool">
|
||||||
<p class="hash">{{ $t(`apiFile.overviewOfMiners`) }}</p>
|
<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.jurisdiction`) }} account</p>
|
||||||
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
||||||
<table border="1">
|
<table border="1">
|
||||||
@@ -1726,7 +1726,7 @@
|
|||||||
<!-- 指定矿机历史24h平均算力 -->
|
<!-- 指定矿机历史24h平均算力 -->
|
||||||
<div class="Pool">
|
<div class="Pool">
|
||||||
<p class="hash">{{ $t(`apiFile.miningMachineHistory24h`) }}</p>
|
<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.jurisdiction`) }} miner</p>
|
||||||
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
<p class="hash">{{ $t(`apiFile.parameter`) }}</p>
|
||||||
<table border="1">
|
<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,
|
FeeShow: true,
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
activeItemCoin:{
|
activeItemCoin: {
|
||||||
value: "nexa",
|
value: "nexa",
|
||||||
label: "nexa",
|
label: "nexa",
|
||||||
img: require("../../assets/img/currency-nexa.png"),
|
img: require("../../assets/img/currency-nexa.png"),
|
||||||
@@ -781,14 +781,14 @@ export default {
|
|||||||
},
|
},
|
||||||
activeItemCoin: {
|
activeItemCoin: {
|
||||||
handler(newVal) {
|
handler(newVal) {
|
||||||
// 防止无限循环
|
// 防止无限循环
|
||||||
if (this.isInternalChange) {
|
if (this.isInternalChange) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.handleActiveItemChange(newVal);
|
this.handleActiveItemChange(newVal);
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
||||||
@@ -832,6 +832,11 @@ export default {
|
|||||||
this.getCoinInfoData(this.params)
|
this.getCoinInfoData(this.params)
|
||||||
this.getPoolPowerData(this.PowerParams)
|
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))
|
this.$addStorageEvent(1, `currencyList`, JSON.stringify(this.currencyList))
|
||||||
if (this.$refs.select) {
|
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;");
|
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`)
|
// let activeItemCoin =localStorage.getItem(`activeItemCoin`)
|
||||||
// this.activeItemCoin=JSON.parse(activeItemCoin)
|
// this.activeItemCoin=JSON.parse(activeItemCoin)
|
||||||
window.addEventListener("setItem", () => {
|
window.addEventListener("setItem", () => {
|
||||||
let value =localStorage.getItem(`activeItemCoin`)
|
let value = localStorage.getItem(`activeItemCoin`)
|
||||||
this.activeItemCoin=JSON.parse(value)
|
this.activeItemCoin = JSON.parse(value)
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1082,12 +1087,12 @@ export default {
|
|||||||
this.inCharts()
|
this.inCharts()
|
||||||
})
|
})
|
||||||
|
|
||||||
}catch{
|
} catch {
|
||||||
console.error('获取数据失败:', error);
|
console.error('获取数据失败:', error);
|
||||||
}finally {
|
} finally {
|
||||||
// 确保无论成功失败都设置loading为false
|
// 确保无论成功失败都设置loading为false
|
||||||
this.setLoading('minerChartLoading', false);
|
this.setLoading('minerChartLoading', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1221,37 +1226,11 @@ export default {
|
|||||||
|
|
||||||
}, 200),
|
}, 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) {
|
getBlockInfoData: Debounce(async function (params) {
|
||||||
// this.reportBlockLoading = true
|
try {
|
||||||
|
// this.reportBlockLoading = true
|
||||||
this.setLoading('reportBlockLoading', true);
|
this.setLoading('reportBlockLoading', true);
|
||||||
const data = await getBlockInfo(params)
|
const data = await getBlockInfo(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
@@ -1259,7 +1238,8 @@ export default {
|
|||||||
this.newBlockInfoData = []
|
this.newBlockInfoData = []
|
||||||
this.BlockInfoData = data.rows
|
this.BlockInfoData = data.rows
|
||||||
if (!this.BlockInfoData[0]) {
|
if (!this.BlockInfoData[0]) {
|
||||||
this.reportBlockLoading = false
|
// this.reportBlockLoading = false
|
||||||
|
this.setLoading('reportBlockLoading', false);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1271,13 +1251,21 @@ export default {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.BlockShow = false
|
this.BlockShow = false
|
||||||
}
|
}
|
||||||
this.setLoading('reportBlockLoading', false);
|
this.setLoading('reportBlockLoading', false);
|
||||||
// this.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) {
|
switch (this.time) {
|
||||||
case "day":
|
case "day":
|
||||||
// this.profit = result.toFixed(10)
|
this.profit = result.toFixed(8)
|
||||||
// this.profit = Math.floor(result * 1e10) / 1e10;
|
// this.profit = Math.floor(result * 1e10) / 1e10;
|
||||||
this.profit = this.toFixedNoRound(result, 10);
|
// this.profit = this.toFixedNoRound(result, 10);
|
||||||
break;
|
break;
|
||||||
case "week":
|
case "week":
|
||||||
// this.profit = (result * 7).toFixed(10)
|
this.profit = (result * 7).toFixed(8)
|
||||||
// this.profit = Math.floor(result * 7 * 1e10) / 1e10;
|
// this.profit = Math.floor(result * 7 * 1e10) / 1e10;
|
||||||
this.profit = this.toFixedNoRound(result * 7, 10);
|
// this.profit = this.toFixedNoRound(result * 7, 10);
|
||||||
break;
|
break;
|
||||||
case "month":
|
case "month":
|
||||||
// this.profit = (result * 30).toFixed(10)
|
this.profit = (result * 30).toFixed(8)
|
||||||
// this.profit = Math.floor(result * 30 * 1e10) / 1e10;
|
// this.profit = Math.floor(result * 30 * 1e10) / 1e10;
|
||||||
this.profit = this.toFixedNoRound(result * 30, 10);
|
// this.profit = this.toFixedNoRound(result * 30, 10);
|
||||||
break;
|
break;
|
||||||
case "year":
|
case "year":
|
||||||
// this.profit = (result * 365).toFixed(10)
|
this.profit = (result * 365).toFixed(8)
|
||||||
// this.profit = Math.floor(result * 365 * 1e10) / 1e10;
|
// this.profit = Math.floor(result * 365 * 1e10) / 1e10;
|
||||||
this.profit = this.toFixedNoRound(result * 365, 10);
|
// this.profit = this.toFixedNoRound(result * 365, 10);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
const nexaFormatter = new Intl.NumberFormat("en-US", {
|
||||||
// 10000000000000000
|
minimumFractionDigits: 2, // 强制显示 2 位小数(不足补零)
|
||||||
|
maximumFractionDigits: 2, // 可选:限制最多 2 位小数(避免多余位数)
|
||||||
const formatter = new Intl.NumberFormat("en-US", {
|
|
||||||
minimumFractionDigits: 10, // 强制显示足够多的小数位
|
|
||||||
useGrouping: true, // 不使用千位分隔符(如 1,000)
|
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位小数 不四舍五入
|
toFixedNoRound(value, decimals = 10) {//保留10位小数 不四舍五入
|
||||||
@@ -1425,14 +1429,14 @@ export default {
|
|||||||
let jumpName = coin.path.charAt(0).toUpperCase() + coin.path.slice(1) //name跳转 首字母大写
|
let jumpName = coin.path.charAt(0).toUpperCase() + coin.path.slice(1) //name跳转 首字母大写
|
||||||
// 使用 name 进行导航,避免重复的路由参数
|
// 使用 name 进行导航,避免重复的路由参数
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
name: jumpName,
|
name: jumpName,
|
||||||
params: {
|
params: {
|
||||||
lang: this.lang,
|
lang: this.lang,
|
||||||
coin: this.params.coin,
|
coin: this.params.coin,
|
||||||
imgUrl: this.currencyPath
|
imgUrl: this.currencyPath
|
||||||
|
|
||||||
},
|
},
|
||||||
replace: false // 保留历史记录,允许回退
|
replace: false // 保留历史记录,允许回退
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -1499,7 +1503,7 @@ export default {
|
|||||||
this.currencyPath = item.imgUrl;
|
this.currencyPath = item.imgUrl;
|
||||||
this.params.coin = item.value;
|
this.params.coin = item.value;
|
||||||
|
|
||||||
console.log( this.params.coin , "item");
|
console.log(this.params.coin, "item");
|
||||||
this.BlockInfoParams.coin = item.value;
|
this.BlockInfoParams.coin = item.value;
|
||||||
this.itemActive = item.value;
|
this.itemActive = item.value;
|
||||||
this.PowerParams.coin = item.value;
|
this.PowerParams.coin = item.value;
|
||||||
@@ -1509,13 +1513,13 @@ export default {
|
|||||||
this.getBlockInfoData(this.BlockInfoParams);
|
this.getBlockInfoData(this.BlockInfoParams);
|
||||||
|
|
||||||
if (this.powerActive) {
|
if (this.powerActive) {
|
||||||
this.handelPower();
|
this.handelPower();
|
||||||
} else {
|
} else {
|
||||||
this.handelMiner();
|
this.handelMiner();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.handelCoinLabel(item.value);
|
this.handelCoinLabel(item.value);
|
||||||
},
|
},
|
||||||
|
|
||||||
clickCurrency(item) {
|
clickCurrency(item) {
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
@@ -1538,8 +1542,8 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// 直接调用处理方法
|
// 直接调用处理方法
|
||||||
this.handleActiveItemChange(item);
|
this.handleActiveItemChange(item);
|
||||||
|
|
||||||
},
|
},
|
||||||
clickReportBlock() {
|
clickReportBlock() {
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
<section v-if="$isMobile">
|
<section v-if="$isMobile">
|
||||||
|
|
||||||
<div class="imgTop">
|
<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-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>
|
</div>
|
||||||
|
|
||||||
@@ -329,13 +329,12 @@
|
|||||||
|
|
||||||
</section>
|
</section>
|
||||||
<div class="content" v-else v-loading="minerChartLoading">
|
<div class="content" v-else v-loading="minerChartLoading">
|
||||||
|
|
||||||
<div class="bgBox">
|
<div class="bgBox">
|
||||||
|
<!--
|
||||||
<img v-if="lang == 'zh'" class="bgBoxImg2Img" src="../../assets/img/enx推广.png" alt="mining" loading="lazy"/>
|
<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 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"/>
|
||||||
|
|
||||||
<!-- <img class="bgBoxImg" src="../../assets/img/enx推广.png" style="width: 100%;height: 100%;" alt="mining" loading="lazy"/> -->
|
|
||||||
</div>
|
</div>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||||
@@ -375,7 +374,7 @@
|
|||||||
<div class="currencyDescription2">
|
<div class="currencyDescription2">
|
||||||
<section class="miningPoolBox">
|
<section class="miningPoolBox">
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
|
<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="interval">
|
||||||
<div class="chartBth">
|
<div class="chartBth">
|
||||||
|
|
||||||
@@ -603,7 +602,7 @@
|
|||||||
<el-row>
|
<el-row>
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
||||||
<div class="reportBlock">
|
<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">
|
<div class="belowTable">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="table-title">
|
<li class="table-title">
|
||||||
@@ -785,6 +784,7 @@ export default {
|
|||||||
p{
|
p{
|
||||||
width: 100% ;
|
width: 100% ;
|
||||||
background: transparent ;
|
background: transparent ;
|
||||||
|
padding-left: 8px;
|
||||||
|
|
||||||
}
|
}
|
||||||
i{
|
i{
|
||||||
@@ -1295,16 +1295,44 @@ export default {
|
|||||||
@media screen and (min-width:800px) and (max-width: 1279px) {
|
@media screen and (min-width:800px) and (max-width: 1279px) {
|
||||||
.imgTop {
|
.imgTop {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
// padding-left: 10%;
|
padding-left: 20%;
|
||||||
text-align: center;
|
text-align: left;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
width: auto ;
|
||||||
|
height:300px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#chart {
|
#chart {
|
||||||
height: 400px !important;
|
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 {
|
.moveCurrencyBox {
|
||||||
@@ -2046,7 +2074,7 @@ export default {
|
|||||||
.bgBox {
|
.bgBox {
|
||||||
// background: gold;
|
// background: gold;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
// height: 380px;
|
height: 300px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
// background-position: 50% 28%;
|
// background-position: 50% 28%;
|
||||||
// background-size: cover;
|
// background-size: cover;
|
||||||
@@ -2059,12 +2087,20 @@ export default {
|
|||||||
// background-position: 13.2vw 0 ;
|
// background-position: 13.2vw 0 ;
|
||||||
// background-repeat: no-repeat;
|
// background-repeat: no-repeat;
|
||||||
// margin-top: 50px;
|
// 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 {
|
.bgBoxImg {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: auto;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 23%;
|
left: 23%;
|
||||||
transition: all 0.3s linear;
|
transition: all 0.3s linear;
|
||||||
|
|||||||
@@ -1346,6 +1346,13 @@ export default {
|
|||||||
this.getHistoryIncomeData(this.IncomeParams)
|
this.getHistoryIncomeData(this.IncomeParams)
|
||||||
this.getHistoryOutcomeData(this.OutcomeParams)
|
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: {
|
methods: {
|
||||||
|
|
||||||
@@ -1400,11 +1407,12 @@ export default {
|
|||||||
// console.log(data,"获取币种信息");
|
// console.log(data,"获取币种信息");
|
||||||
},
|
},
|
||||||
async getMinerAccountPowerData(params) {
|
async getMinerAccountPowerData(params) {
|
||||||
this.powerChartLoading = true
|
// this.powerChartLoading = true
|
||||||
|
this.setLoading('powerChartLoading', true);
|
||||||
const data = await getMinerAccountPower(params)
|
const data = await getMinerAccountPower(params)
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.powerChartLoading = false
|
this.setLoading('powerChartLoading', false);
|
||||||
if (this.myChart) {
|
if (this.myChart) {
|
||||||
this.myChart.dispose()//销毁图表实列
|
this.myChart.dispose()//销毁图表实列
|
||||||
}
|
}
|
||||||
@@ -1437,13 +1445,13 @@ export default {
|
|||||||
this.option.series[1].data = rejectRate
|
this.option.series[1].data = rejectRate
|
||||||
|
|
||||||
this.inCharts()
|
this.inCharts()
|
||||||
this.powerChartLoading = false
|
this.setLoading('powerChartLoading', false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
async getAccountPowerDistributionData(params) {
|
async getAccountPowerDistributionData(params) {
|
||||||
this.barChartLoading = true
|
this.setLoading('barChartLoading', true);
|
||||||
const data = await getAccountPowerDistribution(params)
|
const data = await getAccountPowerDistribution(params)
|
||||||
let barData = data.data
|
let barData = data.data
|
||||||
let xData = []
|
let xData = []
|
||||||
@@ -1455,7 +1463,7 @@ export default {
|
|||||||
this.barOption.xAxis[0].data = xData
|
this.barOption.xAxis[0].data = xData
|
||||||
this.barOption.series[0].data = barValueList
|
this.barOption.series[0].data = barValueList
|
||||||
this.barInCharts()
|
this.barInCharts()
|
||||||
this.barChartLoading = false
|
this.setLoading('barChartLoading', false);
|
||||||
},
|
},
|
||||||
formatNumber(num) {//保留两位小数并补0
|
formatNumber(num) {//保留两位小数并补0
|
||||||
const intPart = Math.floor(num);
|
const intPart = Math.floor(num);
|
||||||
@@ -1463,7 +1471,7 @@ export default {
|
|||||||
return `${intPart}.${String(decimalPart).padStart(2, '0')}`;
|
return `${intPart}.${String(decimalPart).padStart(2, '0')}`;
|
||||||
},
|
},
|
||||||
async getMinerListData(params) {
|
async getMinerListData(params) {
|
||||||
this.MinerListLoading = true
|
this.setLoading('MinerListLoading', true);
|
||||||
const data = await getMinerList(params)
|
const data = await getMinerList(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.MinerListData = data.data
|
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
|
// this.miniLoading=false
|
||||||
// },
|
// },
|
||||||
getMinerPowerData:Debounce(async function(params){
|
getMinerPowerData:Debounce(async function(params){
|
||||||
this.miniLoading=true
|
this.setLoading('miniLoading', true);
|
||||||
const data = await getMinerPower(params)
|
const data = await getMinerPower(params)
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let miniData = data.data
|
let miniData = data.data
|
||||||
@@ -1618,62 +1626,18 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
},200),
|
},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
|
// this.miniLoading=false
|
||||||
// },
|
// },
|
||||||
getMinerPowerOnLine:Debounce(async function(params){
|
getMinerPowerOnLine:Debounce(async function(params){
|
||||||
|
|
||||||
this.miniLoading=true
|
this.setLoading('miniLoading', true);
|
||||||
const data = await getMinerPower(params)
|
const data = await getMinerPower(params)
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let miniData = data.data
|
let miniData = data.data
|
||||||
@@ -1716,7 +1680,7 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
|
|
||||||
|
|
||||||
},200),
|
},200),
|
||||||
@@ -1768,10 +1732,10 @@ export default {
|
|||||||
// this.miniLoading=false
|
// this.miniLoading=false
|
||||||
// },
|
// },
|
||||||
getMinerPowerOffLine:Debounce(async function(params){
|
getMinerPowerOffLine:Debounce(async function(params){
|
||||||
this.miniLoading=true
|
this.setLoading('miniLoading', true);
|
||||||
const data = await getMinerPower(params)
|
const data = await getMinerPower(params)
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let miniData = data.data
|
let miniData = data.data
|
||||||
@@ -1815,7 +1779,7 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
|
|
||||||
|
|
||||||
},200),
|
},200),
|
||||||
|
|||||||
@@ -96,17 +96,20 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetchApiList(this.listParams)
|
this.fetchApiList(this.listParams)
|
||||||
|
this.registerRecoveryMethod('fetchApiList', this.listParams);
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchApiKey(params) {
|
async fetchApiKey(params) {
|
||||||
this.ApiKeyLoading = true
|
this.ApiKeyLoading = true
|
||||||
|
this.setLoading('ApiKeyLoading', true);
|
||||||
const data = await getApiKey(params)
|
const data = await getApiKey(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.fetchApiList(this.listParams)
|
this.fetchApiList(this.listParams)
|
||||||
this.dialogVisible = false
|
this.dialogVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ApiKeyLoading = false
|
this.setLoading('ApiKeyLoading', false);
|
||||||
},
|
},
|
||||||
async fetchApiList(params) {
|
async fetchApiList(params) {
|
||||||
this.apiPageLoading = true
|
this.apiPageLoading = true
|
||||||
@@ -115,7 +118,7 @@ export default {
|
|||||||
this.apiList = data.rows
|
this.apiList = data.rows
|
||||||
}
|
}
|
||||||
|
|
||||||
this.apiPageLoading = false
|
this.setLoading('apiPageLoading', false);
|
||||||
},
|
},
|
||||||
async fetchApiInfo(params) {
|
async fetchApiInfo(params) {
|
||||||
this.apiPageLoading = true
|
this.apiPageLoading = true
|
||||||
@@ -127,7 +130,7 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.apiPageLoading = false
|
this.setLoading('apiPageLoading', false);
|
||||||
},
|
},
|
||||||
async fetchUpdateAPI(params) {
|
async fetchUpdateAPI(params) {
|
||||||
this.apiPageLoading = true
|
this.apiPageLoading = true
|
||||||
@@ -137,7 +140,7 @@ export default {
|
|||||||
this.modifyDialogVisible =false
|
this.modifyDialogVisible =false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.apiPageLoading = false
|
this.setLoading('apiPageLoading', false);
|
||||||
},
|
},
|
||||||
async fetchDelApi(params) {
|
async fetchDelApi(params) {
|
||||||
this.apiPageLoading = true
|
this.apiPageLoading = true
|
||||||
@@ -149,7 +152,7 @@ export default {
|
|||||||
this.fetchApiList(this.listParams)
|
this.fetchApiList(this.listParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.apiPageLoading = false
|
this.setLoading('apiPageLoading', false);
|
||||||
},
|
},
|
||||||
RequestApiKey() {
|
RequestApiKey() {
|
||||||
this.dialogVisible = true
|
this.dialogVisible = true
|
||||||
|
|||||||
@@ -270,6 +270,9 @@ export default {
|
|||||||
|
|
||||||
this.fetchAccountList()
|
this.fetchAccountList()
|
||||||
|
|
||||||
|
this.registerRecoveryMethod('fetchIfBind', "");
|
||||||
|
this.registerRecoveryMethod('fetchAccountList', "");
|
||||||
|
|
||||||
this.currencyList = JSON.parse(localStorage.getItem("currencyList"))
|
this.currencyList = JSON.parse(localStorage.getItem("currencyList"))
|
||||||
window.addEventListener("setItem", () => {
|
window.addEventListener("setItem", () => {
|
||||||
this.currencyList = JSON.parse(localStorage.getItem("currencyList"))
|
this.currencyList = JSON.parse(localStorage.getItem("currencyList"))
|
||||||
@@ -284,7 +287,8 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchIfBind(params){
|
async fetchIfBind(params){
|
||||||
this.securityLoading = true
|
// this.securityLoading = true
|
||||||
|
this.setLoading('securityLoading', true);
|
||||||
const data = await getIfBind(params)
|
const data = await getIfBind(params)
|
||||||
if (data && data.code === 200) {
|
if (data && data.code === 200) {
|
||||||
if (data.data) {
|
if (data.data) {
|
||||||
@@ -302,13 +306,14 @@ export default {
|
|||||||
this.dialogVerification=true
|
this.dialogVerification=true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.securityLoading = false
|
this.setLoading('securityLoading', false);
|
||||||
},
|
},
|
||||||
async fetchCheck(params){
|
async fetchCheck(params){
|
||||||
this.addMinerLoading =true
|
// this.addMinerLoading =true
|
||||||
|
this.setLoading('addMinerLoading', true);
|
||||||
const data = await getCheck(params)
|
const data = await getCheck(params)
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.addMinerLoading =false
|
this.setLoading('addMinerLoading', false);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (data && data.code === 200) {
|
if (data && data.code === 200) {
|
||||||
@@ -320,20 +325,21 @@ export default {
|
|||||||
type: "error",
|
type: "error",
|
||||||
showClose: true
|
showClose: true
|
||||||
});
|
});
|
||||||
this.addMinerLoading =false
|
this.setLoading('addMinerLoading', false);
|
||||||
}else if(data.code === 802){//钱包不可用
|
}else if(data.code === 802){//钱包不可用
|
||||||
this.$message({
|
this.$message({
|
||||||
message: this.$t(`personal.invalidAddress`),
|
message: this.$t(`personal.invalidAddress`),
|
||||||
type: "error",
|
type: "error",
|
||||||
showClose: true
|
showClose: true
|
||||||
});
|
});
|
||||||
this.addMinerLoading =false
|
this.setLoading('addMinerLoading', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetchCheckBalance(params){
|
async fetchCheckBalance(params){
|
||||||
this.confirmBindingLoading =true
|
// this.confirmBindingLoading =true
|
||||||
|
this.setLoading('confirmBindingLoading', true);
|
||||||
const data = await getCheckBalance(params)
|
const data = await getCheckBalance(params)
|
||||||
if (data && data.data) {
|
if (data && data.data) {
|
||||||
this.fetchWalletAddress(this.WalletAddressParams)
|
this.fetchWalletAddress(this.WalletAddressParams)
|
||||||
@@ -344,7 +350,7 @@ export default {
|
|||||||
type: 'error'
|
type: 'error'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.confirmBindingLoading =false
|
this.setLoading('confirmBindingLoading', false);
|
||||||
},
|
},
|
||||||
async fetchAccountGradeList(){
|
async fetchAccountGradeList(){
|
||||||
const data = await getAccountGradeList()
|
const data = await getAccountGradeList()
|
||||||
@@ -369,7 +375,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async fetchMinerAccountBalance(params) {
|
async fetchMinerAccountBalance(params) {
|
||||||
this.MiningLoading = true
|
// this.MiningLoading = true
|
||||||
|
this.setLoading('MiningLoading', true);
|
||||||
const data = await getMinerAccountBalance(params)
|
const data = await getMinerAccountBalance(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.walletDialogVisible = true
|
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.active = this.paymentSettingsData.active==`1` ? this.$t(`personal.no`) :this.$t(`personal.yes`)
|
||||||
|
|
||||||
this.paymentSettingsData.amount = this.paymentSettingsData.amount ? this.paymentSettingsData.amount : `0`
|
this.paymentSettingsData.amount = this.paymentSettingsData.amount ? this.paymentSettingsData.amount : `0`
|
||||||
this.MiningLoading = false
|
this.setLoading('MiningLoading', false);
|
||||||
},
|
},
|
||||||
async fetchDelMinerAccount(params) {
|
async fetchDelMinerAccount(params) {
|
||||||
this.MiningLoading = true
|
// this.MiningLoading = true
|
||||||
|
this.setLoading('MiningLoading', true);
|
||||||
const data = await getDelMinerAccount(params)
|
const data = await getDelMinerAccount(params)
|
||||||
|
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
@@ -400,17 +408,18 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
this.MiningLoading = false
|
this.setLoading('MiningLoading', false);
|
||||||
},
|
},
|
||||||
async fetchAccountList(params) {
|
async fetchAccountList(params) {
|
||||||
this.MiningLoading = true
|
// this.MiningLoading = true
|
||||||
|
this.setLoading('MiningLoading', true);
|
||||||
const data = await getAccountList(params)
|
const data = await getAccountList(params)
|
||||||
this.accountList = data.data
|
this.accountList = data.data
|
||||||
console.log("请求成功,",data);
|
console.log("请求成功,",data);
|
||||||
this.newAccountList = this.accountList
|
this.newAccountList = this.accountList
|
||||||
this.$addStorageEvent(1, `accountList`, JSON.stringify(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) {
|
async fetchAddMinerAccount(params) {
|
||||||
this.addMinerLoading =true
|
// this.addMinerLoading =true
|
||||||
|
this.setLoading('addMinerLoading', true);
|
||||||
const data = await getAddMinerAccount(params)
|
const data = await getAddMinerAccount(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -451,7 +461,7 @@ export default {
|
|||||||
this.fetchAccountList()
|
this.fetchAccountList()
|
||||||
this.fetchAccountGradeList()
|
this.fetchAccountGradeList()
|
||||||
|
|
||||||
this.addMinerLoading =false
|
this.setLoading('addMinerLoading', false);
|
||||||
},
|
},
|
||||||
handleCheckAllChange(val) {
|
handleCheckAllChange(val) {
|
||||||
|
|
||||||
|
|||||||
@@ -197,14 +197,16 @@ export default {
|
|||||||
}))
|
}))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
console.log( this.newMiningAccountList,"isrjiojfeo");
|
|
||||||
|
|
||||||
|
|
||||||
this.fetchUrlList(this.UrlListParams)
|
this.fetchUrlList(this.UrlListParams)
|
||||||
|
this.registerRecoveryMethod('fetchUrlList', this.UrlListParams);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchHtmlUrl(params){
|
async fetchHtmlUrl(params){
|
||||||
this.establishLoading = true
|
// this.establishLoading = true
|
||||||
|
this.setLoading('establishLoading', true);
|
||||||
const data = await getHtmlUrl(params)
|
const data = await getHtmlUrl(params)
|
||||||
|
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
@@ -212,10 +214,11 @@ export default {
|
|||||||
this.dialogVisible=false
|
this.dialogVisible=false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.establishLoading = false
|
this.setLoading('establishLoading', false);
|
||||||
},
|
},
|
||||||
async fetchUrlList(params){
|
async fetchUrlList(params){
|
||||||
this.UrlListLoading = true
|
// this.UrlListLoading = true
|
||||||
|
this.setLoading('UrlListLoading', true);
|
||||||
const data = await getUrlList(params)
|
const data = await getUrlList(params)
|
||||||
console.log(data,666 );
|
console.log(data,666 );
|
||||||
|
|
||||||
@@ -223,7 +226,7 @@ export default {
|
|||||||
|
|
||||||
this.TotalSize = data.total
|
this.TotalSize = data.total
|
||||||
|
|
||||||
this.UrlListLoading = false
|
this.setLoading('UrlListLoading', false);
|
||||||
},
|
},
|
||||||
async fetchUrlInfo(params){
|
async fetchUrlInfo(params){
|
||||||
const data = await getUrlInfo(params)
|
const data = await getUrlInfo(params)
|
||||||
@@ -239,7 +242,8 @@ export default {
|
|||||||
|
|
||||||
},
|
},
|
||||||
async fetchChangeUrlInfo(params){
|
async fetchChangeUrlInfo(params){
|
||||||
this.modifyLoading=true
|
// this.modifyLoading=true
|
||||||
|
this.setLoading('modifyLoading', true);
|
||||||
const data = await getChangeUrlInfo(params)
|
const data = await getChangeUrlInfo(params)
|
||||||
console.log(data);
|
console.log(data);
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
@@ -248,7 +252,7 @@ export default {
|
|||||||
console.log("修改成功");
|
console.log("修改成功");
|
||||||
|
|
||||||
}
|
}
|
||||||
this.modifyLoading=false
|
this.setLoading('modifyLoading', false);
|
||||||
|
|
||||||
},
|
},
|
||||||
async fetchDelete(params){
|
async fetchDelete(params){
|
||||||
|
|||||||
@@ -155,13 +155,14 @@ export default {
|
|||||||
|
|
||||||
this.lang = this.$i18n.locale; // 初始化语言值
|
this.lang = this.$i18n.locale; // 初始化语言值
|
||||||
this.fetchIfBind()
|
this.fetchIfBind()
|
||||||
|
this.registerRecoveryMethod('fetchIfBind', "");
|
||||||
if (this.$route.params.active) {
|
if (this.$route.params.active) {
|
||||||
this.handelVerification()
|
this.handelVerification()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async fetchIfBind(params) {
|
async fetchIfBind(params) {
|
||||||
this.securityLoading = true
|
this.setLoading('securityLoading', true);
|
||||||
const data = await getIfBind(params)
|
const data = await getIfBind(params)
|
||||||
if (data && data.code === 200) {
|
if (data && data.code === 200) {
|
||||||
if (data.data) {
|
if (data.data) {
|
||||||
@@ -170,10 +171,10 @@ export default {
|
|||||||
this.isItBound = false
|
this.isItBound = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.securityLoading = false
|
this.setLoading('securityLoading', false);
|
||||||
},
|
},
|
||||||
async fetchBindInfo(params) {
|
async fetchBindInfo(params) {
|
||||||
this.BindInfoLoading = true
|
this.setLoading('BindInfoLoading', true);
|
||||||
const data = await getBindInfo(params)
|
const data = await getBindInfo(params)
|
||||||
console.log(data, "绑定信息");
|
console.log(data, "绑定信息");
|
||||||
if (data && data.code === 200) {
|
if (data && data.code === 200) {
|
||||||
@@ -182,10 +183,10 @@ export default {
|
|||||||
this.dialogVisible = false
|
this.dialogVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.BindInfoLoading = false
|
this.setLoading('BindInfoLoading', false);
|
||||||
},
|
},
|
||||||
async fetchBindGoogle(params) {
|
async fetchBindGoogle(params) {
|
||||||
this.BindInfoLoading = true
|
this.setLoading('BindInfoLoading', true);
|
||||||
const data = await getBindGoogle(params)
|
const data = await getBindGoogle(params)
|
||||||
console.log(data, "绑定");
|
console.log(data, "绑定");
|
||||||
if (data && data.code === 200) {
|
if (data && data.code === 200) {
|
||||||
@@ -203,7 +204,7 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
this.BindInfoLoading = false
|
this.setLoading('BindInfoLoading', false);
|
||||||
},
|
},
|
||||||
async fetchBindCode(params) {
|
async fetchBindCode(params) {
|
||||||
const data = await getBindCode(params)
|
const data = await getBindCode(params)
|
||||||
@@ -216,7 +217,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async fetchResetPwd(params) {
|
async fetchResetPwd(params) {
|
||||||
this.ResetPwdLoading = true
|
this.setLoading('ResetPwdLoading', true);
|
||||||
const data = await getUpdatePwd(params)
|
const data = await getUpdatePwd(params)
|
||||||
if (data && data.code === 200) {
|
if (data && data.code === 200) {
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -230,7 +231,7 @@ export default {
|
|||||||
localStorage.removeItem("token")
|
localStorage.removeItem("token")
|
||||||
this.$router.push(`/${lang}/login`);
|
this.$router.push(`/${lang}/login`);
|
||||||
}
|
}
|
||||||
this.ResetPwdLoading = false
|
this.setLoading('ResetPwdLoading', false);
|
||||||
},
|
},
|
||||||
async fetchResetPwdCode(params) {
|
async fetchResetPwdCode(params) {
|
||||||
const data = await getUpdatePwdCode(params)
|
const data = await getUpdatePwdCode(params)
|
||||||
@@ -244,7 +245,7 @@ export default {
|
|||||||
|
|
||||||
},
|
},
|
||||||
async fetchCloseStepTwo(params) {
|
async fetchCloseStepTwo(params) {
|
||||||
this.closeLoading = true
|
this.setLoading('closeLoading', true);
|
||||||
const data = await getCloseStepTwo(params)
|
const data = await getCloseStepTwo(params)
|
||||||
if (data && data.code === 200) {
|
if (data && data.code === 200) {
|
||||||
this.$message({
|
this.$message({
|
||||||
@@ -260,7 +261,7 @@ export default {
|
|||||||
this.closeParams[key] = ""
|
this.closeParams[key] = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.closeLoading = false
|
this.setLoading('closeLoading', false);
|
||||||
},
|
},
|
||||||
async fetchCloseCode(params) {
|
async fetchCloseCode(params) {
|
||||||
const data = await getCloseCode(params)
|
const data = await getCloseCode(params)
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export default {
|
|||||||
value:"enx",
|
value:"enx",
|
||||||
label:"Entropyx(Enx)",
|
label:"Entropyx(Enx)",
|
||||||
img:`${this.$baseApi}img/enx.svg`,
|
img:`${this.$baseApi}img/enx.svg`,
|
||||||
rate:"0",
|
rate:"1%",
|
||||||
address:"",
|
address:"",
|
||||||
mode:"PPLNS+PROPDIF",
|
mode:"PPLNS+PROPDIF",
|
||||||
quota:"5000",
|
quota:"5000",
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
<template slot="title">
|
<template slot="title">
|
||||||
<div class="collapseTitle">
|
<div class="collapseTitle">
|
||||||
<span ><img :src="item.img" alt="coin" loading="lazy"> {{item.label}}</span>
|
<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-if="item.value === 'enx'"> {{ $t(`course.timeLimited`) }} 0%</span> -->
|
||||||
<span v-else>{{item.rate}}</span>
|
<span >{{item.rate}}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<section class="contentBox2">
|
<section class="contentBox2">
|
||||||
@@ -76,8 +76,8 @@
|
|||||||
<li v-for="item in rateList" :key="item.value">
|
<li v-for="item in rateList" :key="item.value">
|
||||||
<span class="coin"><img :src="item.img" alt="coin" loading="lazy"> {{item.label}}</span>
|
<span class="coin"><img :src="item.img" alt="coin" loading="lazy"> {{item.label}}</span>
|
||||||
<span>{{item.address}}</span>
|
<span>{{item.address}}</span>
|
||||||
<span v-if="item.value === 'enx'"> {{ $t(`course.timeLimited`) }} 0%</span>
|
<!-- <span v-if="item.value === 'enx'"> {{ $t(`course.timeLimited`) }} 0%</span> -->
|
||||||
<span v-else>{{item.rate}}</span>
|
<span >{{item.rate}}</span>
|
||||||
<span>{{item.mode}}</span>
|
<span>{{item.mode}}</span>
|
||||||
<span>{{item.quota}}</span>
|
<span>{{item.quota}}</span>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1228,6 +1228,8 @@ export default {
|
|||||||
this.getMinerAccountPowerData(this.PowerParams)
|
this.getMinerAccountPowerData(this.PowerParams)
|
||||||
this.getAccountPowerDistributionData(this.PowerDistribution)
|
this.getAccountPowerDistributionData(this.PowerDistribution)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"$i18n.locale":(val)=>{
|
"$i18n.locale":(val)=>{
|
||||||
location.reload();//刷新页面 刷新echarts
|
location.reload();//刷新页面 刷新echarts
|
||||||
@@ -1271,6 +1273,12 @@ export default {
|
|||||||
this.getAccountPowerDistributionData(this.PowerDistribution)
|
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: {
|
methods: {
|
||||||
|
|
||||||
@@ -1320,7 +1328,7 @@ export default {
|
|||||||
},
|
},
|
||||||
//返回权限 1矿工 2收益 3支付
|
//返回权限 1矿工 2收益 3支付
|
||||||
async fetchPageInfo(params){
|
async fetchPageInfo(params){
|
||||||
this.jurisdictionLoading = true
|
this.setLoading('jurisdictionLoading', true);
|
||||||
const data = await getPageInfo(params)
|
const data = await getPageInfo(params)
|
||||||
console.log(data);
|
console.log(data);
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
@@ -1354,7 +1362,7 @@ export default {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.jurisdictionLoading = false
|
this.setLoading('jurisdictionLoading', false);
|
||||||
},
|
},
|
||||||
//获取当前挖矿账号信息(包含收益、余额)
|
//获取当前挖矿账号信息(包含收益、余额)
|
||||||
async getMinerAccountInfoData(params) {
|
async getMinerAccountInfoData(params) {
|
||||||
@@ -1362,11 +1370,11 @@ export default {
|
|||||||
this.MinerAccountData = data.data
|
this.MinerAccountData = data.data
|
||||||
},
|
},
|
||||||
async getMinerAccountPowerData(params) {
|
async getMinerAccountPowerData(params) {
|
||||||
this.powerChartLoading = true
|
this.setLoading('powerChartLoading', true);
|
||||||
const data = await getMinerAccountPower(params)
|
const data = await getMinerAccountPower(params)
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.powerChartLoading = false
|
this.setLoading('powerChartLoading', false);
|
||||||
if (this.myChart) {
|
if (this.myChart) {
|
||||||
this.myChart.dispose()//销毁图表实列
|
this.myChart.dispose()//销毁图表实列
|
||||||
}
|
}
|
||||||
@@ -1399,13 +1407,13 @@ export default {
|
|||||||
this.option.series[1].data = rejectRate
|
this.option.series[1].data = rejectRate
|
||||||
|
|
||||||
this.inCharts()
|
this.inCharts()
|
||||||
this.powerChartLoading = false
|
this.setLoading('powerChartLoading', false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
async getAccountPowerDistributionData(params) {
|
async getAccountPowerDistributionData(params) {
|
||||||
this.barChartLoading = true
|
this.setLoading('barChartLoading', true);
|
||||||
const data = await getAccountPowerDistribution(params)
|
const data = await getAccountPowerDistribution(params)
|
||||||
let barData = data.data
|
let barData = data.data
|
||||||
let xData = []
|
let xData = []
|
||||||
@@ -1417,7 +1425,7 @@ export default {
|
|||||||
this.barOption.xAxis[0].data = xData
|
this.barOption.xAxis[0].data = xData
|
||||||
this.barOption.series[0].data = barValueList
|
this.barOption.series[0].data = barValueList
|
||||||
this.barInCharts()
|
this.barInCharts()
|
||||||
this.barChartLoading = false
|
this.setLoading('barChartLoading', false);
|
||||||
},
|
},
|
||||||
formatNumber(num) {//保留两位小数并补0
|
formatNumber(num) {//保留两位小数并补0
|
||||||
const intPart = Math.floor(num);
|
const intPart = Math.floor(num);
|
||||||
@@ -1425,7 +1433,7 @@ export default {
|
|||||||
return `${intPart}.${String(decimalPart).padStart(2, '0')}`;
|
return `${intPart}.${String(decimalPart).padStart(2, '0')}`;
|
||||||
},
|
},
|
||||||
async getMinerListData(params) {
|
async getMinerListData(params) {
|
||||||
this.MinerListLoading = true
|
this.setLoading('MinerListLoading', true);
|
||||||
const data = await getMinerList(params)
|
const data = await getMinerList(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.MinerListData = data.data
|
this.MinerListData = data.data
|
||||||
@@ -1451,17 +1459,17 @@ export default {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.MinerListLoading = false
|
this.setLoading('MinerListLoading', false);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
//小图
|
//小图
|
||||||
async getMinerPowerData(params) {
|
async getMinerPowerData(params) {
|
||||||
this.miniLoading=true
|
this.setLoading('miniLoading', true);
|
||||||
const data = await getMinerPower(params)
|
const data = await getMinerPower(params)
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let miniData = data.data
|
let miniData = data.data
|
||||||
@@ -1507,15 +1515,15 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
},
|
},
|
||||||
//小图
|
//小图
|
||||||
async getMinerPowerOnLine(params) {
|
async getMinerPowerOnLine(params) {
|
||||||
this.miniLoading=true
|
this.setLoading('miniLoading', true);
|
||||||
const data = await getMinerPower(params)
|
const data = await getMinerPower(params)
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let miniData = data.data
|
let miniData = data.data
|
||||||
@@ -1556,14 +1564,14 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
},
|
},
|
||||||
//小图
|
//小图
|
||||||
async getMinerPowerOffLine(params) {
|
async getMinerPowerOffLine(params) {
|
||||||
this.miniLoading=true
|
this.setLoading('miniLoading', true);
|
||||||
const data = await getMinerPower(params)
|
const data = await getMinerPower(params)
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let miniData = data.data
|
let miniData = data.data
|
||||||
@@ -1605,7 +1613,7 @@ export default {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.miniLoading=false
|
this.setLoading('miniLoading', false);
|
||||||
},
|
},
|
||||||
async getHistoryIncomeData(params) {
|
async getHistoryIncomeData(params) {
|
||||||
const data = await getHistoryIncome(params)
|
const data = await getHistoryIncome(params)
|
||||||
|
|||||||
@@ -235,6 +235,10 @@ export default {
|
|||||||
|
|
||||||
this.getLuckData(this.params)
|
this.getLuckData(this.params)
|
||||||
this.getBlockInfoData(this.BlockInfoParams)
|
this.getBlockInfoData(this.BlockInfoParams)
|
||||||
|
|
||||||
|
this.registerRecoveryMethod('getLuckData', this.params);
|
||||||
|
this.registerRecoveryMethod('getBlockInfoData', this.BlockInfoParams);
|
||||||
|
|
||||||
let value = localStorage.getItem("activeItemCoin")
|
let value = localStorage.getItem("activeItemCoin")
|
||||||
this.activeItemCoin = JSON.parse(value)
|
this.activeItemCoin = JSON.parse(value)
|
||||||
this.currencyList = JSON.parse(localStorage.getItem("currencyList"))
|
this.currencyList = JSON.parse(localStorage.getItem("currencyList"))
|
||||||
@@ -260,14 +264,14 @@ export default {
|
|||||||
// },
|
// },
|
||||||
|
|
||||||
getLuckData: Debounce(async function (params) {
|
getLuckData: Debounce(async function (params) {
|
||||||
this.LuckDataLoading = true
|
this.setLoading('LuckDataLoading', true);
|
||||||
const data = await getLuck(params)
|
const data = await getLuck(params)
|
||||||
if (data && data.code == 200) {
|
if (data && data.code == 200) {
|
||||||
this.luckData = data.data
|
this.luckData = data.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.LuckDataLoading = false
|
this.setLoading('LuckDataLoading', false);
|
||||||
}, 200),
|
}, 200),
|
||||||
// async getBlockInfoData(params) {
|
// async getBlockInfoData(params) {
|
||||||
// this.reportBlockLoading=true
|
// this.reportBlockLoading=true
|
||||||
@@ -286,10 +290,10 @@ export default {
|
|||||||
// },
|
// },
|
||||||
getBlockInfoData: Debounce(async function (params) {
|
getBlockInfoData: Debounce(async function (params) {
|
||||||
|
|
||||||
this.reportBlockLoading = true
|
this.setLoading('reportBlockLoading', true);
|
||||||
const data = await getBlockInfo(params)
|
const data = await getBlockInfo(params)
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.reportBlockLoading = false
|
this.setLoading('reportBlockLoading', false);
|
||||||
}
|
}
|
||||||
this.totalSize = data.total
|
this.totalSize = data.total
|
||||||
this.BlockInfoData = data.rows
|
this.BlockInfoData = data.rows
|
||||||
@@ -298,7 +302,7 @@ export default {
|
|||||||
})
|
})
|
||||||
// this.currentPage = 1
|
// this.currentPage = 1
|
||||||
// console.log(data,"获取币种信息");
|
// console.log(data,"获取币种信息");
|
||||||
this.reportBlockLoading = false
|
this.setLoading('reportBlockLoading', false);
|
||||||
|
|
||||||
}, 200),
|
}, 200),
|
||||||
handleActiveItemChange(item) {
|
handleActiveItemChange(item) {
|
||||||
@@ -314,6 +318,9 @@ export default {
|
|||||||
clickCurrency(item) {
|
clickCurrency(item) {
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
// 设置标记,防止触发 watch
|
// 设置标记,防止触发 watch
|
||||||
|
|
||||||
|
this.luckData={}
|
||||||
|
|
||||||
this.isInternalChange = true;
|
this.isInternalChange = true;
|
||||||
this.activeItemCoin = item;
|
this.activeItemCoin = item;
|
||||||
this.$addStorageEvent(1, `activeItemCoin`, JSON.stringify(item))
|
this.$addStorageEvent(1, `activeItemCoin`, JSON.stringify(item))
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
</el-menu>
|
</el-menu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="luckyBox" >
|
<div class="luckyBox" v-show="this.activeItemCoin.value != 'enx' && this.activeItemCoin.value != 'alph'">
|
||||||
|
|
||||||
<div class="luckyItem">
|
<div class="luckyItem">
|
||||||
<span class="title">{{$t(`home.lucky3`)}}</span>
|
<span class="title">{{$t(`home.lucky3`)}}</span>
|
||||||
@@ -125,7 +125,8 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<!-- v-loading = "LuckDataLoading" -->
|
<!-- v-loading = "LuckDataLoading" -->
|
||||||
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
|
<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">
|
<div class="luckyItem">
|
||||||
<span class="title">{{$t(`home.lucky3`)}}</span>
|
<span class="title">{{$t(`home.lucky3`)}}</span>
|
||||||
|
|||||||
@@ -1,153 +1,397 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="width: 1300px; height: 600px">
|
<div>
|
||||||
<div id="chart" style="width: 100%; height: 100%; min-width: 500px"></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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
import * as echarts from "echarts";
|
import { ref, onMounted, onUnmounted, nextTick, watch } from 'vue'
|
||||||
export default {
|
import { Stomp } from '@stomp/stompjs'
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
countDownTime: 60,
|
|
||||||
timer: null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
const props = defineProps({
|
||||||
let base = +new Date(1968, 9, 3);
|
msg: {
|
||||||
let oneDay = 24 * 3600 * 1000;
|
type: String,
|
||||||
let date = [];
|
required: true
|
||||||
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("/"));
|
const message = ref('')
|
||||||
data.push(Math.round((Math.random() - 0.5) * 20 + data[i - 1]));
|
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 个空数据在前后
|
stompClient.value.connect(
|
||||||
for (let i = 0; i < 100; i++) {
|
connectHeaders,
|
||||||
date.unshift(null);
|
function(frame) {
|
||||||
data.unshift(null);
|
console.log('连接成功: ' + frame)
|
||||||
}
|
console.log('连接时间:', connectTime.value?.toLocaleString())
|
||||||
for (let i = 0; i < 100; i++) {
|
isConnected.value = true
|
||||||
date.push(null);
|
isConnecting.value = false
|
||||||
data.push(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
var option = {
|
// 添加系统消息
|
||||||
tooltip: {
|
receivedMessages.value.push({
|
||||||
trigger: "axis",
|
sender: 'System',
|
||||||
position: function (pt) {
|
content: '已连接到聊天服务器',
|
||||||
return [pt[0], "10%"];
|
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: {
|
function(error) {
|
||||||
left: "center",
|
console.error('连接失败:', error)
|
||||||
text: "Large Area Chart",
|
isConnected.value = false
|
||||||
},
|
isConnecting.value = false
|
||||||
toolbox: {
|
connectionError.value = `连接失败: ${error.headers?.message || error.message || '未知错误'}`
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
},
|
} catch (error) {
|
||||||
methods: {
|
console.error('初始化WebSocket客户端失败:', error)
|
||||||
//初始化图表
|
isConnected.value = false
|
||||||
inCharts() {
|
isConnecting.value = false
|
||||||
if (this.myChart == null) {
|
connectionError.value = `初始化失败: ${error.message || '未知错误'}`
|
||||||
this.myChart = echarts.init(document.getElementById("chart"));
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加断开连接方法
|
||||||
|
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`);
|
stompClient.value.send(
|
||||||
this.option.series[1].name = this.$t(`home.currencyPrice`);
|
`/point/send/message`,
|
||||||
|
{},
|
||||||
|
JSON.stringify(messageObj)
|
||||||
|
)
|
||||||
|
|
||||||
this.myChart.setOption(this.option);
|
// 添加自己发送的消息到显示列表
|
||||||
// 回调函数,在渲染完成后执行
|
receivedMessages.value.push({
|
||||||
this.myChart.on("finished", () => {
|
sender: email.value,
|
||||||
// 在这里执行显示给用户的操作
|
content: message.value.trim(),
|
||||||
// console.log('图表渲染完成,显示给用户');
|
timestamp: new Date().toISOString(),
|
||||||
this.minerChartLoading = false;
|
isSelf: true
|
||||||
});
|
})
|
||||||
// window.addEventListener("resize", () => {
|
|
||||||
// if (this.myChart) this.myChart.resize();
|
|
||||||
// });
|
|
||||||
|
|
||||||
window.addEventListener(
|
message.value = ''
|
||||||
"resize",
|
} catch (error) {
|
||||||
throttle(() => {
|
console.error('发送消息失败:', error)
|
||||||
if (this.myChart) this.myChart.resize();
|
|
||||||
}, 200)
|
receivedMessages.value.push({
|
||||||
);
|
sender: 'System',
|
||||||
},
|
content: `发送失败: ${error.message || '未知错误'}`,
|
||||||
startCountDown() {
|
timestamp: new Date().toISOString(),
|
||||||
this.timer = setInterval(() => {
|
error: true
|
||||||
if (this.countDownTime <= 0) {
|
})
|
||||||
//当监测到countDownTime为0时,清除计数器并且移除sessionStorage,然后执行提交试卷逻辑
|
}
|
||||||
clearInterval(this.timer);
|
} else {
|
||||||
sessionStorage.removeItem("exam_time");
|
connectionError.value = '连接已断开,请重新连接'
|
||||||
alert("提交试卷");
|
isConnected.value = false
|
||||||
} else if (this.countDownTime > 0) {
|
}
|
||||||
//每秒让countDownTime -1秒,并设置到sessionStorage中
|
}
|
||||||
this.countDownTime--;
|
|
||||||
window.sessionStorage.setItem("exam_time", this.countDownTime);
|
// 组件卸载时断开连接
|
||||||
}
|
onUnmounted(() => {
|
||||||
}, 1000);
|
if (stompClient.value?.connected) {
|
||||||
},
|
stompClient.value.disconnect()
|
||||||
},
|
}
|
||||||
};
|
})
|
||||||
</script>
|
</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,"文件返回");
|
console.log(res,"文件返回");
|
||||||
|
|
||||||
this.ruleForm.files = res.data.data.id
|
this.ruleForm.files = res.data.data.id
|
||||||
if (this.ruleForm.files) {//成功拿到返回ID
|
// if (this.ruleForm.files) {//成功拿到返回ID
|
||||||
this.fetchSubmitWork(this.ruleForm)
|
// this.fetchSubmitWork(this.ruleForm)
|
||||||
}
|
// }
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ export default {
|
|||||||
this.workOrderId = localStorage.getItem("workOrderId")
|
this.workOrderId = localStorage.getItem("workOrderId")
|
||||||
if (this.workOrderId) {
|
if (this.workOrderId) {
|
||||||
this.fetchTicketDetails({ id: this.workOrderId })
|
this.fetchTicketDetails({ id: this.workOrderId })
|
||||||
|
this.registerRecoveryMethod('fetchTicketDetails', { id: this.workOrderId });
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.faultList = JSON.parse(localStorage.getItem('faultList') )
|
// this.faultList = JSON.parse(localStorage.getItem('faultList') )
|
||||||
|
|||||||
@@ -198,18 +198,22 @@ export default {
|
|||||||
case `all`:
|
case `all`:
|
||||||
this.params.status = 0
|
this.params.status = 0
|
||||||
this.fetchRechargeRecord0(this.params)
|
this.fetchRechargeRecord0(this.params)
|
||||||
|
this.registerRecoveryMethod('fetchRechargeRecord0', this.params);
|
||||||
break;
|
break;
|
||||||
case `pending`:
|
case `pending`:
|
||||||
this.params.status = 2
|
this.params.status = 2
|
||||||
this.fetchRechargeRecord2(this.params)
|
this.fetchRechargeRecord2(this.params)
|
||||||
|
this.registerRecoveryMethod('fetchRechargeRecord2', this.params);
|
||||||
break;
|
break;
|
||||||
case `Finished`:
|
case `Finished`:
|
||||||
this.params.status = 10
|
this.params.status = 10
|
||||||
this.fetchRechargeRecord10(this.params)
|
this.fetchRechargeRecord10(this.params)
|
||||||
|
this.registerRecoveryMethod('fetchRechargeRecord10', this.params);
|
||||||
break;
|
break;
|
||||||
case `pendingProcessing`:
|
case `pendingProcessing`:
|
||||||
this.params.status = 1
|
this.params.status = 1
|
||||||
this.fetchRechargeRecord1(this.params)
|
this.fetchRechargeRecord1(this.params)
|
||||||
|
this.registerRecoveryMethod('fetchRechargeRecord1', this.params);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -95,14 +95,17 @@ export default {
|
|||||||
case "pending":
|
case "pending":
|
||||||
this.params.status = 1
|
this.params.status = 1
|
||||||
this.fetchPrivateConsume1(this.params)
|
this.fetchPrivateConsume1(this.params)
|
||||||
|
this.registerRecoveryMethod('fetchPrivateConsume1', this.params);
|
||||||
break;
|
break;
|
||||||
case "success"://已完成工单
|
case "success"://已完成工单
|
||||||
this.params.status = 2
|
this.params.status = 2
|
||||||
this.fetchPrivateConsume2(this.params)
|
this.fetchPrivateConsume2(this.params)
|
||||||
|
this.registerRecoveryMethod('fetchPrivateConsume2', this.params);
|
||||||
break;
|
break;
|
||||||
case "reply"://全部工单
|
case "reply"://全部工单
|
||||||
this.params.status = 0
|
this.params.status = 0
|
||||||
this.fetchPrivateConsume0(this.params)
|
this.fetchPrivateConsume0(this.params)
|
||||||
|
this.registerRecoveryMethod('fetchPrivateConsume0', this.params);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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: /admin
|
||||||
Disallow: /oapi #禁止爬取oapi和api开头的接口内容
|
Disallow: /oapi #禁止爬取oapi和api开头的接口内容
|
||||||
Disallow: /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