1.1需求处理、修改请求地址IP

1.广播页面及功能 接口对接 完成更新正式网
 2.用户管理页面  处理中
 3.工单管理 完成
 4.用户算力
This commit is contained in:
2025-06-27 16:45:47 +08:00
parent 2111eedabb
commit 62260e8483
55 changed files with 1208 additions and 511 deletions

View File

@@ -20,11 +20,31 @@ export function sendMail(data) {
}
// //发送邮件给用户
// export function sendMail(data) {
// return request({
// url: `manage/user/get/user/info`,
// method: 'post',
// data
// })
// }
//获取单个用户详情
export function getUserDetails(data) {
return request({
url: `manage/user/get/user/info`,
method: 'post',
data
})
}
//用户详情曲线图
export function getUserLineChart(data) {
return request({
url: `manage/user/getMiningPowerInfo`,
method: 'post',
data
})
}
//用户离线柱状图
export function getUserOnlineStatus(data) {
return request({
url: `manage/user/getMinerUserOnlineStatus`,
method: 'post',
data
})
}

View File

@@ -49,8 +49,13 @@
<comAside></comAside>
<!-- 主体内容 -->
<el-main class="admin-main">
<router-view v-if="key !== '/'" :key="key" />
<el-main class="admin-main">
<router-view v-if="key !== '/zh' && key !== '/en' &&key !== '/zh/login' && key !== '/en/login' && key !== '/zh/register' && key !== '/en/register'" :key="key" />
<div v-else style="color: #333;font-size: 16px;text-align: center;line-height: 100vh;">
选择左侧导航栏查看页面
</div>
</el-main>
</el-container>
</el-container>

File diff suppressed because it is too large Load Diff

View File

@@ -49,20 +49,20 @@ export default {
id:"1",
},
// {//用户管理
// path:"userManagement",
// label:`backendSystem.userManagement`,
// icon:"el-icon-user",
// id:"2",
{//用户管理
path:"userManagement",
label:`backendSystem.userManagement`,
icon:"el-icon-user",
id:"2",
// },
// {//工单管理
// path:"workOrderBackend",
// label:`backendSystem.workOrder`,
// icon:"el-icon-document-copy",
// id:"3",
},
{//工单管理
path:"workOrderBackend",
label:`backendSystem.workOrder`,
icon:"el-icon-document-copy",
id:"3",
// },
},
// {//用户算力
// path:"userComputingPower",
// label:`backendSystem.userComputingPower`,
@@ -71,29 +71,36 @@ export default {
// },
],
activeIndex:"1",
activeIndex: "0",
}
},
mounted(){
if(localStorage.getItem("activeIndex")){
this.activeIndex = localStorage.getItem("activeIndex");
const savedIndex = localStorage.getItem("activeIndex");
if(savedIndex){
this.activeIndex = savedIndex;
}else{
this.$addStorageEvent(1, "activeIndex", this.activeIndex);
this.activeIndex ="1"
}
}
},
methods:{
handleClick(item){
this.activeIndex = item.id;
this.$addStorageEvent(1, "activeIndex", item.id);
console.log(item,'item');
const lang = this.$i18n.locale;
this.$router.push(`/${lang}/${item.path}`);
this.activeIndex = item.id;
this.$addStorageEvent(1, "activeIndex", item.id);
}
},
beforeDestroy(){
localStorage.removeItem("activeIndex");
}
};
</script>

View File

@@ -175,8 +175,8 @@
<span class="line"></span>
</div>
</li>
<li
<!-- 工单管理 -->
<!-- <li
v-show="ManagementShow"
class="personalCenter"
:class="{
@@ -193,7 +193,7 @@
<span class="circular"></span>
<span class="line"></span>
</div>
</li>
</li> -->
<li class="langBox">
<div class="LangLine"></div>

View File

@@ -26,7 +26,7 @@ Vue.use(ElementUI, {
});
Vue.prototype.$axios = axios
console.log = ()=>{} //全局关闭打印
// console.log = ()=>{} //全局关闭打印
// 全局注册混入
Vue.mixin(loadingStateMixin);//loading状态管理
Vue.mixin(networkRecoveryMixin);//网络恢复后数据刷新
@@ -36,6 +36,10 @@ const screenWidth = window.innerWidth || document.documentElement.clientWidth ||
const isNarrowScreen = screenWidth < 1280;
Vue.prototype.$isMobile = isNarrowScreen
// 在路由守卫中设置
router.beforeEach((to, from, next) => {
// 从路由中获取语言参数

View File

@@ -86,7 +86,7 @@ const childrenRoutes = [
}
}
},
{//报块页面
{//用户管理
path: 'userManagement',
name: 'UserManagement',
component: () => import('../views/userManagement/index.vue'),
@@ -97,8 +97,23 @@ const childrenRoutes = [
en: 'userManagement',
zh: '用户管理'
}
},
},
{//用户详情
path: 'userDetails',
name: 'UserDetails',
component: () => import('../views/userDetails/index.vue'),
meta: {title: '用户详情',
description:i18n.t(`seo.userManagement`),
allAuthority:[`admin`,`back_admin`],
keywords:{
en: 'userDetails',
zh: '用户详情'
}
}
},
{//费率
@@ -662,88 +677,167 @@ const router = new VueRouter({
router.beforeEach((to, from, next) => {
// 检查语言参数
const lang = to.params.lang;
const supportedLanguages = ['zh', 'en'];
// router.beforeEach((to, from, next) => {
// 如果路径以斜杠结尾且不是根路径,则重定向
if (to.path.endsWith('/') && to.path.length > 1) {
const path = to.path.slice(0, -1);
return next({
path,
query: to.query,
hash: to.hash,
params: to.params
});
}
// // 检查语言参数
// const lang = to.params.lang;
// const supportedLanguages = ['zh', 'en'];
// // 如果路径以斜杠结尾且不是根路径,则重定向
// if (to.path.endsWith('/') && to.path.length > 1) {
// const path = to.path.slice(0, -1);
// return next({
// path,
// query: to.query,
// hash: to.hash,
// params: to.params
// });
// }
if (!lang && to.path !== '/') {
const defaultLang = localStorage.getItem('lang') || 'en';
return next(`/${defaultLang}${to.path}`);
}
// if (!lang && to.path !== '/') {
// const defaultLang = localStorage.getItem('lang') || 'en';
// return next(`/${defaultLang}${to.path}`);
// }
let data = localStorage.getItem("jurisdiction");
let jurisdiction =JSON.parse(data);
console.log(jurisdiction,"权限");
// let data = localStorage.getItem("jurisdiction");
// let jurisdiction =JSON.parse(data);
// console.log(jurisdiction,"权限");
localStorage.setItem('superReportError',"")
let element = document.getElementsByClassName('el-main')[0];
if(element){
element.scrollTop = 0
}
// localStorage.setItem('superReportError',"")
// let element = document.getElementsByClassName('el-main')[0];
// if(element){
// element.scrollTop = 0
// }
let token
try{
token =JSON.parse(localStorage.getItem('token'))
}catch(e){
console.log(e);
}
// let token
// try{
// token =JSON.parse(localStorage.getItem('token'))
// }catch(e){
// console.log(e);
// }
// console.log('beforeEach:', to.path, 'token:', token);
if (token) {
// if (token) {
if (to.path === `/${lang}/login`|| to.path === `/${lang}/register`) {
next({ path: `/${lang}` })
}else if(to.meta.allAuthority && to.meta.allAuthority[0] ==`all`){
next()
}else if(jurisdiction.roleKey && to.meta.allAuthority&&to.meta.allAuthority.some(item=>item == jurisdiction.roleKey )){
next()
}else{
console.log(to.meta.allAuthority,to.path,"权限");
// if (to.path === `/${lang}/login`|| to.path === `/${lang}/register`) {
// next({ path: `/${lang}` })
// }else if(to.meta.allAuthority && to.meta.allAuthority[0] ==`all`){
// next()
// }else if(jurisdiction.roleKey && to.meta.allAuthority&&to.meta.allAuthority.some(item=>item == jurisdiction.roleKey )){
// next()
// }else{
// console.log(to.meta.allAuthority,to.path,"权限");
Message({//权限不足
showClose: true,
message:i18n.t(`mining.jurisdiction`),
type: 'error'
});
// Message({//权限不足
// showClose: true,
// message:i18n.t(`mining.jurisdiction`),
// type: 'error'
// });
next({ path: `/${lang}` }) // 添加这行,重定向到首页
}
// next({ path: `/${lang}` }) // 添加这行,重定向到首页
// }
}else{
// }else{
// console.log(to.path,"to.path 权限不足");
// let paths = [`/${lang}/miningAccount`,`/${lang}/workOrderRecords`,`/${lang}/userWorkDetails`,`/${lang}/submitWorkOrder`,`/${lang}/workOrderBackend`,`/${lang}/BKWorkDetails`]
// if (paths.includes(to.path) || to.path.includes(`personalCenter`) ) {
// console.log(to.path,"to.path 权限不足");
let paths = [`/${lang}/miningAccount`,`/${lang}/workOrderRecords`,`/${lang}/userWorkDetails`,`/${lang}/submitWorkOrder`,`/${lang}/workOrderBackend`,`/${lang}/BKWorkDetails`]
if (paths.includes(to.path) || to.path.includes(`personalCenter`) ) {
Message({//权限不足
showClose: true,
message:i18n.t(`mining.logInFirst`),
type: 'error'
});
// Message({//权限不足
// showClose: true,
// message:i18n.t(`mining.logInFirst`),
// type: 'error'
// });
next({ path: `/${lang}/login` })
} else {
// next({ path: `/${lang}/login` })
// } else {
next()
}
}
// next()
// }
// return; // 防止多次 next
// }
})
// })
router.beforeEach((to, from, next) => {
const lang = to.params.lang || (localStorage.getItem('lang') || 'en');
let token = null;
try {
token = JSON.parse(localStorage.getItem('token'));
} catch (e) {
token = null;
}
// 需要登录的页面
const needLoginPaths = [
`/${lang}/miningAccount`,
`/${lang}/workOrderRecords`,
`/${lang}/userWorkDetails`,
`/${lang}/submitWorkOrder`,
`/${lang}/workOrderBackend`,
`/${lang}/BKWorkDetails`
];
// 未登录
if (!token) {
// 只在不是登录/注册页时才跳转
if (
(needLoginPaths.includes(to.path) || to.path.includes('personalCenter')) &&
to.name !== 'Login' &&
to.name !== 'Register'
) {
Message({
showClose: true,
message: i18n.t(`mining.logInFirst`),
type: 'error'
});
return next({ path: `/${lang}/login` });
}
return next();
}
// 已登录
if (to.name === 'Login' || to.name === 'Register') {
return next({ path: `/${lang}` });
}
// 权限判断
let jurisdiction = null;
try {
jurisdiction = JSON.parse(localStorage.getItem("jurisdiction"));
} catch (e) {
jurisdiction = null;
}
if (
to.meta.allAuthority &&
(
to.meta.allAuthority[0] === 'all' ||
(jurisdiction && jurisdiction.roleKey && to.meta.allAuthority.includes(jurisdiction.roleKey))
)
) {
return next();
}
// 无权限
Message({
showClose: true,
message: i18n.t(`mining.jurisdiction`),
type: 'error'
});
return next({ path: `/${lang}/login` }); // 建议无权限时跳转登录页而不是首页
});

View File

@@ -91,7 +91,7 @@ export const getImageUrl = (path) => {
const baseUrl = process.env.VUE_APP_BASE_URL;
if (!path) return '';
if (path.startsWith('http')) {
return path.replace('https://test.m2pool.com', baseUrl);
return path.replace('http://test.m2pool.com', baseUrl);
}
return `${baseUrl}${path.startsWith('/') ? '' : '/'}${path}`;
};

View File

@@ -326,8 +326,8 @@ export default {
if (!this.activeCoin) {
this.activeCoin = "nexa"
this.imgUrl = `https://test.m2pool.com/img/nexa.png`
this.currencyPath = `https://test.m2pool.com/img/nexa.png`
this.imgUrl = `${this.$baseApi}/img/nexa.png`
this.currencyPath = `${this.$baseApi}/img/nexa.png`
this.params.coin = "nexa"
this.$addStorageEvent(1, `activeCoin`, JSON.stringify(this.activeCoin))
this.openAPI = true

View File

@@ -73,13 +73,12 @@ export default {
this.activeCoin= JSON.parse(activeCoin)
});
console.log(this.activeCoin,"鸡脚低端局");
if ( !this.activeCoin ) {
this.activeCoin ="nexa"
this.imgUrl = `https://test.m2pool.com/img/nexa.png`
this.currencyPath= `https://test.m2pool.com/img/nexa.png`
this.imgUrl = `${this.$baseApi}/img/nexa.png`
this.currencyPath= `${this.$baseApi}/img/nexa.png`
this.params.coin ="nexa"
this.$addStorageEvent(1,`activeCoin`,JSON.stringify(this.activeCoin))
this.openAPI =true

View File

@@ -422,21 +422,26 @@ export default {
}
.main {
width: 100%;
min-height: 100vh;
background: #fff;
background-image: url(../../assets/img/miningAccount/top.png);
background-size: 100% 50%;
background-repeat: no-repeat;
background-position: 30% -15%;
// background-image: url(../../assets/img/miningAccount/top.png);
// background-size: 100% 50%;
// background-repeat: no-repeat;
// background-position: 30% -15%;
padding: 0;
margin: 0;
padding-top: 60PX;
// padding-top: 60PX;
display: flex;
justify-content: center;
height: 100%;
overflow-y: auto;
}
.content{
width: 50%;
width: 100%;
margin: 0 auto;
padding: 20px;
box-sizing: border-box;
}
.elBtn{
background: #661FFB;

View File

@@ -588,9 +588,15 @@ export default {
if (this.stompClient) {
this.forceDisconnectAll();
}
console.log("开始初始化WebSocket连接...");
const baseUrl = process.env.VUE_APP_BASE_API.replace("https", "wss");
let apiUrl = process.env.VUE_APP_BASE_API;
let baseUrl=""
// 将 https 替换为 wss
if (apiUrl.startsWith("https://")) {
baseUrl= apiUrl.replace("https://", "wss://");
}
if (apiUrl.startsWith("http://")) {
baseUrl=apiUrl.replace("http://", "ws://");
}
const wsUrl = `${baseUrl}chat/ws`;
this.stompClient = Stomp.client(wsUrl);

View File

@@ -902,7 +902,7 @@ export default {
this.$addStorageEvent(1, `currencyList`, JSON.stringify(this.currencyList))
if (this.$refs.select) {
this.$refs.select.$el.children[0].children[0].setAttribute('style', "background:url(https://test.m2pool.com/img/nexa.png) no-repeat 10PX;background-size: 20PX 20PX;color:#333;padding-left: 30PX;");
this.$refs.select.$el.children[0].children[0].setAttribute('style', `background:url(${this.$baseApi}/img/nexa.png) no-repeat 10PX;background-size: 20PX 20PX;color:#333;padding-left: 30PX;`);
}
this.fetchParam({ coin: this.params.coin })

View File

@@ -0,0 +1,113 @@
import { getUserDetails,getUserLineChart,getUserOnlineStatus } from '../../api/userManagement'
export default {
name: 'UserDetails',
data() {
return {
userDetailsID: null,
userData: {
// address:"D7tviVPKtTd2qnkzJEVfZWQqzV6NyQqHxw",
// historyBalance:[
// {
// "balance": "testAddBalanceForgrD7tviVPKtTd2qnkzJEVfZWQqzV6NyQqHxws"
// },
// {
// "balance": "testAddBalancD7tviVPKtTd2qnkzJEVfZWQqzV6NyQqHxweForgrs"
// },
// {
// "balance": "testAddBalancD7tviVPKtTd2qnkzJEVfZWQqzV6NyQqHxweForgrs"
// },
// ],
// maxHeight:"100000",
// createDate:"2025-06-16 00:00:00",
// amount:"273920.96662387",
// coin:"nexa",
// shouldOutDate:"2025-06-16 00:00:00",
// user:"ceshi1",
},
userDetailsLoading: false,
formInline: {
user: '',
region: ''
},
userDetailsParams:{
coin: '',
minerUser: '',
},
labelPosition: 'top',
noDataTip: false,
lineChartParams:{
user: '',
endDate:"",
startDate:"",
coin:"",
},
onlineStatusParams:{
user: '',
coin: '',
datePoint:"",
}
}
},
mounted() {
console.log('userDetails mounted', this.$route.path, this.$route.query)
const params= this.$route.query || JSON.parse(localStorage.getItem("userDetailsParams"));
this.lineChartParams.user=params.user
this.lineChartParams.coin=params.coin
this.onlineStatusParams.user=params.user
this.onlineStatusParams.coin=params.coin
this.userDetailsParams.coin=params.coin
this.userDetailsParams.minerUser=params.minerUser
if (this.userDetailsParams.coin && this.userDetailsParams.minerUser) {
localStorage.setItem("userDetailsParams", JSON.stringify(params));
this.fetchUserDetails(this.userDetailsParams);
this.fetchUserLineChart(this.lineChartParams);
this.fetchUserOnlineStatus(this.onlineStatusParams);
}
},
methods: {
async fetchUserDetails(params) {
this.userDetailsLoading = true
// 这里写你的获取详情逻辑
const res = await getUserDetails(params)
console.log(res)
if(res && res.code == 200){
if (!res.data) {
// this.$message.error('未获取到用户信息');
this.noDataTip = true
this.userData.coin = this.userDetailsParams.coin
this.userData.user = this.userDetailsParams.minerUser
}else{
this.userData = res.data
this.userData.shouldOutDate=`${this.userData.shouldOutDate.split("T")[0]} ${this.userData.shouldOutDate.split("T")[1]}`
this.userData.createDate=`${this.userData.createDate.split("T")[0]} ${this.userData.createDate.split("T")[1]}`
this.noDataTip = false
}
}
this.userDetailsLoading = false
},
async fetchUserLineChart(params) {
const res = await getUserLineChart(params)
console.log(res)
},
async fetchUserOnlineStatus(params) {
const res = await getUserOnlineStatus(params)
console.log(res)
},
goBack(){
const lang = this.$i18n.locale;
this.$router.push({
path: `/${lang}/userManagement`,
})
},
}
}

View File

@@ -0,0 +1,178 @@
<template>
<div v-loading="userDetailsLoading">
<div class="main-title">用户详情 <span @click="goBack" style="color: #409EFF;cursor: pointer;font-size: 16px;">返回</span> </div>
<section class="user-details-box">
<section class="user-details-form">
<el-form
:label-position="labelPosition"
:inline="true"
:model="userData"
class="demo-form-inline"
>
<el-row>
<el-col :span="8">
<el-form-item style="width: 80%;" label="币种:" label-width="100px" prop="coin">
<el-input disabled v-model="userData.coin"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item style="width: 80%;" label="挖矿账户:" label-width="100px" prop="user">
<el-input disabled v-model="userData.user"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item style="width: 80%;" label="交易金额:" label-width="100px" prop="amount">
<el-input disabled v-model="userData.amount"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item
label="收益分配日期:"
label-width="100px"
prop="createDate"
style="width: 80%;"
>
<el-input disabled v-model="userData.createDate"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item style="width: 80%;" label="最大高度:" label-width="100px" prop="maxHeight">
<el-input disabled v-model="userData.maxHeight"></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item style="width: 80%;" label="实际转账日期:" label-width="100px" prop="shouldOutDate">
<el-input disabled v-model="userData.shouldOutDate"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item style="width: 55%;" label="转账地址:" label-width="100px" prop="address">
<el-input
disabled v-model="userData.address"
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item style="width: 55%; max-height: 300px;overflow-y: auto;" label="历史支付地址:" label-width="100px" prop="address">
<p class="history-balance-item" v-for="item in userData.historyBalance" :key="item.balance">{{item.balance}}</p>
</el-form-item>
</el-col>
</el-row>
</el-form>
</section>
<section class="chartBox">
<div class="lineChartBox">用户挖矿曲线图</div>
<div class="barChartBox">柱状图</div>
</section>
</section>
</div>
</template>
<script>
import Index from "./index";
export default {
mixins: [Index],
};
</script>
<style lang="scss" scoped>
.main-title {
font-size: 24px;
font-weight: bold;
color: #333;
margin-bottom: 18px;
}
.user-details-box{
width: 100%;
margin: 0 auto;
box-sizing: border-box;
padding: 20px;
background-color: #fff;
border-radius: 10px;
margin-bottom: 20px;
height: 73vh;
overflow: hidden;
overflow-y: auto;
// background: palegoldenrod;
}
.user-details-form {
width: 80%;
box-sizing: border-box;
padding: 20px;
background-color: #fff;
border-radius: 10px;
margin-bottom: 20px;
// background: palegoldenrod;
}
.no-data-tip{
width: 80%;
margin: 0 auto;
font-size: 16px;
color: #999;
text-align: center;
margin-top: 20px;
}
.history-balance-item{
margin: 0;
padding: 0;
background:#E7DFF3 ;
padding: 0px 20px;
border-radius: 20px;
margin-bottom: 10px;
color: rgba(0,0,0,0.6);
}
::v-deep .el-form-item__label {
// color: #409EFF; /* 例如设置为 Element UI 主色 */
font-weight: bold; /* 加粗 */
font-size: 16px; /* 字号 */
letter-spacing: 1px; /* 字间距 */
/* 你可以根据需要添加更多样式 */
}
.chartBox{
width: 80vw;
box-sizing: border-box;
// background: palegoldenrod;
height: 800px;
display: flex;
align-content: center;
justify-content: space-around;
}
.lineChartBox{
width: 49%;
height: 100%;
background: palegoldenrod;
}
.barChartBox{
width: 49%;
height: 100%;
background: pink;
}
</style>

View File

@@ -1,34 +1,223 @@
import { getUserList, sendMail } from '../../api/userManagement'
import { getUserList, sendMail, } from '../../api/userManagement'
export default {
data(){
data() {
return {
userList:[],
userListLoading:false,
userListParams:{
coin:"nexa",
minerUser:"",
user:"",
pageNum:1,
pageSize:50
userList: [],
userListLoading: false,
userListParams: {
coin: "nexa",
minerUser: "",
user: "",
pageNum: 1,
pageSize: 50
},
tableData:[],
userManagementLoading:false,
tableData: [],
userManagementLoading: false,
formInline: {
user: "",
region: "",
},
currencyList: [],
screenCurrency: 'nexa',
rules: {
user: [
{
type: 'email',
message: '请输入正确的邮箱地址',
trigger: ['blur', 'change']
}
]
},
emailRules: {
subject: [
{ required: true, message: '请输入邮件主题', trigger: 'blur' }
],
text: [
{ required: true, message: '请输入邮件内容', trigger: 'blur' }
],
to: [
{
/**
* 多邮箱校验+去重,支持中英文逗号分隔
* @param {Object} rule
* @param {string} value
* @param {Function} callback
*/
validator: (rule, value, callback) => {
if (!value) {
callback(); // 允许为空
return;
}
// 以中英文逗号分隔,去除首尾空格
const emails = value.split(/[,]/).map(e => e.trim()).filter(e => e);
// 邮箱正则
const emailReg = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;
// 检查格式
for (let email of emails) {
if (!emailReg.test(email)) {
callback(new Error('请输入正确的邮箱地址,多个邮箱用逗号分隔'));
return;
}
}
// 检查去重(忽略大小写)
const lowerSet = new Set();
for (let email of emails) {
const lower = email.toLowerCase();
if (lowerSet.has(lower)) {
callback(new Error('存在重复邮箱,请检查'));
return;
}
lowerSet.add(lower);
}
callback();
},
trigger: ['blur', 'change']
}
]
},
dialogVisible: false,
senParams:{
subject:"",
text:"",
to:"",
},
sendEmailLoading: false,
}
},
mounted(){
this.fetchUserList(this.userListParams);
},
methods:{
async fetchUserList(params){
this.userManagementLoading = true;
const data = await getUserList(params);
console.log(data,'data');
mounted() {
let token
try{
token =JSON.parse(localStorage.getItem('token'))
}catch(e){
console.log(e);
}
if (token) {
if(data && data.code == 200){
this.fetchUserList(this.userListParams);
}
this.currencyList = JSON.parse(localStorage.getItem("currencyList"))
window.addEventListener("setItem", () => {
this.currencyList = JSON.parse(localStorage.getItem("currencyList"))
});
this.changeScreen(this.screenCurrency);
},
methods: {
async fetchUserList(params) {
this.setLoading('userManagementLoading', true);
const data = await getUserList(params);
if (data && data.code == 200) {
this.tableData = data.rows;
}
this.userManagementLoading = false;
this.setLoading('userManagementLoading', false);
},
async fetchSendEmail(params) {
this.setLoading('sendEmailLoading', true);
const data = await sendMail(params);
if (data && data.code == 200) {
this.$message.success('发送成功');
this.dialogVisible = false;
for (const key in this.senParams) {
this.senParams[key] = "";
}
}
this.setLoading('sendEmailLoading', false);
},
changeScreen(scope) {
let brand = scope
for (let index in this.currencyList) {
let aa = this.currencyList[index];
let value = aa.value;
if (brand === value) {
this.$refs.screen.$el.children[0].children[0].setAttribute('style', "background:url(" + aa.imgUrl + ") no-repeat 10PX;background-size: 20PX 20PX;color:#333;padding-left: 33PX;");
}
}
this.userListParams.coin = scope
this.fetchUserList(this.userListParams);
},
handelImg(coin) {
return this.currencyList.find(item => item.value === coin)?.imgUrl || '';
},
handelQuery() {
this.$refs.formRef.validate((valid) => {
if (valid) {
for (let key in this.userListParams) {
if (typeof this.userListParams[key] === 'string') {
this.userListParams[key] = this.userListParams[key].trim();
}
}
if (!this.userListParams.minerUser && !this.userListParams.user) {
this.$message.error('请输入查询条件(挖矿账号、邮箱)');
return;
}
this.fetchUserList(this.userListParams);
}
});
},
sendEmail(row) {
this.dialogVisible = true;
this.senParams.to = row.user;
},
/**
* 输入框清除后自动重新查询
*/
handleInputClear() {
this.fetchUserList(this.userListParams);
},
handleClose() {
this.dialogVisible = false;
},
handleInput(val, type) {
},
sureSendEmail(){
console.log(this.senParams,'this.senParams');
this.$refs.formRef.validate((valid) => {
if (valid) {
this.fetchSendEmail(this.senParams);
}
});
},
handleDetails(row){
console.log(row,'row');
// 获取当前语言
const lang = this.$i18n.locale;
// 添加语言参数的路由跳转
this.$router.push({
path: `/${lang}/userDetails`,
query: { coin: row.coin,minerUser:row.minerUser, user: row.user,}
}).catch(err => {
if(err.name !== 'NavigationDuplicated') {
console.error('路由跳转失败:', err);
}
});
let obj ={
coin: row.coin,
minerUser: row.minerUser,
user: row.user,
}
// 保存ID到localStorage
localStorage.setItem("userDetailsParams",JSON.stringify(obj));
}
}
}

View File

@@ -1,95 +1,139 @@
<template>
<div v-loading="userManagementLoading">
<div class="main-title">注册用户管理</div>
<div class="main-title">注册用户管理</div>
<el-table
:data="tableData"
border
style="width: 100%; margin-bottom: 18px"
:header-cell-style="{ 'text-align': 'center' }"
:cell-style="{ 'text-align': 'center' }"
height="65vh"
>
<el-table-column prop="id" label="ID" width="60" />
<el-table-column prop="coin" label="币种" />
<el-table-column prop="user" label="用户邮箱" />
<el-table-column prop="status" label="用户状态" />
<el-table-column prop="minerUser" label="挖矿账号" />
<el-form :inline="true" :model="userListParams" class="demo-form-inline" :rules="rules" ref="formRef">
<el-form-item label="币种:" prop="coin">
<el-select
class="input"
size="middle"
ref="screen"
@change="changeScreen(screenCurrency)"
v-model="screenCurrency"
:placeholder="$t(`personal.screen`)"
>
<el-option
v-for="item in currencyList"
:key="item.value"
:label="item.label"
:value="item.value"
>
<div style="display: flex; align-items: center">
<img :src="item.imgUrl" style="float: left; width: 20px" />
<span style="float: left; margin-left: 5px">
{{ item.label }}</span
>
</div>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="挖矿账号:" style="margin-left: 5vw" prop="minerUser">
<el-input v-model="userListParams.minerUser" placeholder="挖矿账号" clearable @clear="handleInputClear"></el-input>
</el-form-item>
<el-form-item label="邮箱:" style="margin-left: 5vw" prop="user">
<el-input
v-model="userListParams.user"
type="email"
placeholder="邮箱"
clearable
@clear="handleInputClear"
></el-input>
</el-form-item>
<el-table-column :label="$t('backendSystem.operation')" width="200">
<el-button
size="mini"
>详情</el-button>
<el-button
size="mini"
>发送邮件</el-button>
</el-table-column>
<el-form-item style="margin-left: 1vw">
<el-button type="primary" @click="handelQuery">查询</el-button>
</el-form-item>
</el-form>
<el-table
:data="tableData"
border
style="width: 100%; margin-bottom: 18px"
:header-cell-style="{ 'text-align': 'center' }"
:cell-style="{ 'text-align': 'center' }"
height="65vh"
>
<el-table-column prop="id" label="ID" width="60" />
<el-table-column prop="coin" label="币种" width="100" show-overflow-tooltip>
<template slot-scope="scope" >
<div style="display: flex; align-items: center;justify-content: center;">
<img :src="handelImg(scope.row.coin)" style="width: 20px" />
<span style="margin-left: 5px">{{ scope.row.coin }}</span>
</div>
</template>
</el-table-column>
<el-table-column prop="user" label="用户邮箱" width="200" show-overflow-tooltip/>
<el-table-column prop="amount" label="最小起付金额" width="100" show-overflow-tooltip/>
<el-table-column prop="status" label="用户状态" width="80">
<template slot-scope="scope">
<el-tag :type="scope.row.status === '1' ? 'success' : 'danger'">{{
scope.row.status == "0" ? "正常" : "删除"
}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="minerUser" label="挖矿账号" width="180" show-overflow-tooltip/>
<el-table-column prop="balance" label="支付地址" show-overflow-tooltip />
<el-table-column prop="active" label="是否自动提现" width="80" show-overflow-tooltip>
<template slot-scope="scope">
<el-tag :type="scope.row.active === '1' ? 'success' : 'danger'">{{
scope.row.active == "0" ? "是" : "否"
}}</el-tag>
</template>
</el-table-column>
</el-table>
<el-table-column :label="$t('backendSystem.operation')" width="180">
<template slot-scope="scope">
<el-button size="mini" @click="handleDetails(scope.row)" type="primary" plain>详情</el-button>
<el-button size="mini" @click="sendEmail(scope.row)" style="color: #651fff; border: 1px solid #651fff"
>发送邮件</el-button
>
</template>
</el-table-column>
</el-table>
<!-- 新增广播弹窗 -->
<!-- <el-dialog
:title="$t('backendSystem.dialogTitle')"
<!-- 发送邮箱弹窗-->
<el-dialog
title="邮件内容"
:visible.sync="dialogVisible"
width="50%"
:before-close="handleClose"
:close-on-click-modal="false"
:close-on-click-modal="false"
>
<el-form :model="addParams" >
<el-form-item >
<el-input resize="none" v-model="addParams.content" type="textarea" :rows="5" @input="val => handleInput(val, 'add')" />
<div v-if="isOverLimit" style="color: #999; font-size: 12px; margin-top: 4px;">{{$t("backendSystem.exceedingInput")}}</div>
<el-form :model="senParams" ref="formRef" :rules="emailRules">
<el-form-item label="收件人" prop="to">
<el-input maxlength="500" resize="none" v-model="senParams.to" type="textarea" :rows="2" />
<div style="color: #999; font-size: 12px; margin-top: 4px;">可输入多个邮箱用逗号隔开</div>
</el-form-item>
<el-form-item label="邮件主题" prop="subject">
<el-input resize="none" maxlength="300" show-word-limit v-model="senParams.subject" type="textarea" :rows="3" />
</el-form-item>
<el-form-item label="邮件内容" prop="text">
<el-input resize="none" maxlength="600" show-word-limit v-model="senParams.text" type="textarea" :rows="8" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="handleClose">{{$t("backendSystem.cancel")}}</el-button>
<el-button type="primary" :loading="bthLoading" @click="sureAddBroadcast">{{$t("backendSystem.publish")}}</el-button>
<el-button type="primary" :loading="sendEmailLoading" @click="sureSendEmail">发送</el-button>
</div>
</el-dialog> -->
<!-- 修改广播弹窗 -->
<!-- <el-dialog
:title="$t('backendSystem.editContent')"
:visible.sync="editDialogVisible"
width="50%"
:before-close="handleEditClose"
:close-on-click-modal="false"
>
<el-form :model="editParams" >
<el-form-item >
<el-input resize="none" v-model="editParams.content" type="textarea" :rows="5" @input="val => handleInput(val, 'edit')" />
<div v-if="isOverLimit" style="color: #999; font-size: 12px; margin-top: 4px;">{{$t("backendSystem.exceedingInput")}}</div>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="handleEditClose">{{$t("backendSystem.cancel")}}</el-button>
<el-button type="primary" :loading="editLoading" @click="sureEditBroadcast">{{$t("backendSystem.editBroadcast")}}</el-button>
</div>
</el-dialog> -->
</div>
</el-dialog>
</div>
</template>
<script>
import Index from './index'
import Index from "./index";
export default {
mixins:[Index],
}
mixins: [Index],
};
</script>
<style lang="scss" scoped>
.main-title{
.main-title {
font-size: 24px;
font-weight: bold;
color: #333;
margin-bottom: 18px;
}
</style>

View File

@@ -686,19 +686,19 @@ export default {
width: 100%;
min-height: 100vh;
background: #fff;
background-image: url(../../assets/img/miningAccount/top.png);
background-size: 100% 50%;
background-repeat: no-repeat;
background-position: 30% -15%;
// background-image: url(../../assets/img/miningAccount/top.png);
// background-size: 100% 50%;
// background-repeat: no-repeat;
// background-position: 30% -15%;
padding: 0;
margin: 0;
padding-top: 60PX;
// padding-top: 60PX;
display: flex;
justify-content: center;
}
.workBKContent{
width: 60%;
width: 100%;
margin: 0 auto;
}