周五定时更新
This commit is contained in:
@@ -7,6 +7,7 @@ ENV = 'development'
|
|||||||
#开发环境
|
#开发环境
|
||||||
VUE_APP_BASE_API = 'https://test.m2pool.com/api/'
|
VUE_APP_BASE_API = 'https://test.m2pool.com/api/'
|
||||||
# VUE_APP_BASE_API = 'http://18.183.240.108:8080/api/'
|
# VUE_APP_BASE_API = 'http://18.183.240.108:8080/api/'
|
||||||
|
# VUE_APP_BASE_API = 'http://10.168.2.220:8888'
|
||||||
VUE_APP_BASE_URL = 'https://test.m2pool.com/'
|
VUE_APP_BASE_URL = 'https://test.m2pool.com/'
|
||||||
# 路由懒加载
|
# 路由懒加载
|
||||||
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ VUE_APP_TITLE = m2pool
|
|||||||
ENV = 'production'
|
ENV = 'production'
|
||||||
|
|
||||||
# 生产环境
|
# 生产环境
|
||||||
VUE_APP_BASE_API = 'https://m2pool.com/api/'
|
# VUE_APP_BASE_API = 'https://m2pool.com/api/'
|
||||||
|
VUE_APP_BASE_API = 'http://10.168.2.220:8888'
|
||||||
VUE_APP_BASE_URL = 'https://m2pool.com/'
|
VUE_APP_BASE_URL = 'https://m2pool.com/'
|
||||||
|
|
||||||
# 路由懒加载
|
# 路由懒加载
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ NODE_ENV = production
|
|||||||
ENV = 'staging'
|
ENV = 'staging'
|
||||||
|
|
||||||
# 测试环境
|
# 测试环境
|
||||||
# VUE_APP_BASE_API = 'http://18.183.240.108:8080/api/'
|
VUE_APP_BASE_API = 'http://10.168.2.220:8888'
|
||||||
VUE_APP_BASE_API = 'https://test.m2pool.com/api/'
|
# VUE_APP_BASE_API = 'https://test.m2pool.com/api/'
|
||||||
VUE_APP_BASE_URL = 'https://test.m2pool.com/'
|
VUE_APP_BASE_URL = 'https://test.m2pool.com/'
|
||||||
|
|
||||||
|
|
||||||
# 路由懒加载
|
# 路由懒加载
|
||||||
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||||
@@ -18,6 +18,9 @@ body{
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #2c3e50;
|
color: #2c3e50;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
|
|||||||
@@ -25,4 +25,10 @@ body,html,*{
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
.el-main{
|
||||||
|
// background: palegoldenrod;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
// overflow-x: hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -92,11 +92,10 @@ export function deleteShopConfig(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 钱包配置(用于修改卖家钱包地址)----获取链(一级)和币(二级) 下拉列表(获取本系统支持的链和币种)
|
||||||
// 批量删除购物车中已下架商品
|
export function getChainAndCoin(data) {
|
||||||
export function deleteBatchGoodsForIsDelete(data) {
|
|
||||||
return request({
|
return request({
|
||||||
url: `/lease/shopping/cart/deleteBatchGoodsForIsDelete`,
|
url: `/lease/shop/getChainAndCoin`,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
@@ -107,3 +106,8 @@ export function deleteBatchGoodsForIsDelete(data) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
power_leasing/src/assets/imgs/commodity.png
Normal file
BIN
power_leasing/src/assets/imgs/commodity.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
@@ -124,8 +124,8 @@ export const accountRoutes = [
|
|||||||
name: 'accountShopConfig',
|
name: 'accountShopConfig',
|
||||||
component: () => import('../views/account/shopConfig.vue'),
|
component: () => import('../views/account/shopConfig.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: '店铺配置',
|
title: '钱包绑定',
|
||||||
description: '配置店铺收款和支付方式',
|
description: '绑定店铺收款钱包',
|
||||||
allAuthority: ['all']
|
allAuthority: ['all']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -180,7 +180,7 @@ export const accountRoutes = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'purchased-detail/:orderItemId',
|
path: 'purchased-detail/:id',
|
||||||
name: 'PurchasedDetail',
|
name: 'PurchasedDetail',
|
||||||
component: () => import('../views/account/purchasedDetail.vue'),
|
component: () => import('../views/account/purchasedDetail.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ function decryptData(encryptedText, secretKey) {
|
|||||||
return {
|
return {
|
||||||
// 敏感数据(已解密)
|
// 敏感数据(已解密)
|
||||||
token: sensitiveData?.token || '',
|
token: sensitiveData?.token || '',
|
||||||
userEmail: sensitiveData?.userEmail || '',
|
leasEmail: sensitiveData?.leasEmail || '',
|
||||||
userId: sensitiveData?.userId || '',
|
userId: sensitiveData?.userId || '',
|
||||||
timestamp: sensitiveData?.timestamp || null,
|
timestamp: sensitiveData?.timestamp || null,
|
||||||
|
|
||||||
@@ -61,8 +61,8 @@ function decryptData(encryptedText, secretKey) {
|
|||||||
/**
|
/**
|
||||||
* 执行自动登录
|
* 执行自动登录
|
||||||
*/
|
*/
|
||||||
function performAutoLogin(token, userId, userEmail) {
|
function performAutoLogin(token, userId, leasEmail) {
|
||||||
console.log('执行自动登录:', { userId, userEmail: userEmail ? '***' : '' });
|
console.log('执行自动登录:', { userId, leasEmail: leasEmail ? '***' : '' });
|
||||||
// 这里可以添加自动登录的逻辑
|
// 这里可以添加自动登录的逻辑
|
||||||
// 例如:设置全局状态、跳转页面等
|
// 例如:设置全局状态、跳转页面等
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ function decryptData(encryptedText, secretKey) {
|
|||||||
console.log(params.token,"params.token 存入");
|
console.log(params.token,"params.token 存入");
|
||||||
|
|
||||||
localStorage.setItem('token', params.token);
|
localStorage.setItem('token', params.token);
|
||||||
localStorage.setItem('userEmail', params.userEmail);
|
localStorage.setItem('leasEmail', params.leasEmail);
|
||||||
localStorage.setItem('userId', params.userId);
|
localStorage.setItem('userId', params.userId);
|
||||||
localStorage.setItem('language', params.language);
|
localStorage.setItem('language', params.language);
|
||||||
localStorage.setItem('username', params.username);
|
localStorage.setItem('username', params.username);
|
||||||
@@ -93,7 +93,7 @@ function decryptData(encryptedText, secretKey) {
|
|||||||
|
|
||||||
console.log('接收到的参数:', {
|
console.log('接收到的参数:', {
|
||||||
userId: params.userId ? '***' : '',
|
userId: params.userId ? '***' : '',
|
||||||
userEmail: params.userEmail ? '***' : '',
|
leasEmail: params.leasEmail ? '***' : '',
|
||||||
token: params.token ? '***' : '',
|
token: params.token ? '***' : '',
|
||||||
language: params.language,
|
language: params.language,
|
||||||
username: params.username,
|
username: params.username,
|
||||||
@@ -103,7 +103,7 @@ function decryptData(encryptedText, secretKey) {
|
|||||||
// 根据参数执行相应操作
|
// 根据参数执行相应操作
|
||||||
if (params.token && params.userId) {
|
if (params.token && params.userId) {
|
||||||
// 执行自动登录
|
// 执行自动登录
|
||||||
performAutoLogin(params.token, params.userId, params.userEmail);
|
performAutoLogin(params.token, params.userId, params.leasEmail);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.language) {
|
if (params.language) {
|
||||||
|
|||||||
@@ -28,8 +28,23 @@
|
|||||||
<el-table-column label="总金额(USDT)" min-width="140">
|
<el-table-column label="总金额(USDT)" min-width="140">
|
||||||
<template #default="scope"><span class="value strong">{{ (scope.row && scope.row.totalPrice) != null ? scope.row.totalPrice : '—' }}</span></template>
|
<template #default="scope"><span class="value strong">{{ (scope.row && scope.row.totalPrice) != null ? scope.row.totalPrice : '—' }}</span></template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="已支付金额(USDT)" min-width="140">
|
<el-table-column min-width="180">
|
||||||
<template #default="scope"><span class="value strong">{{ (scope.row && scope.row.payAmount) != null ? scope.row.payAmount : '—' }}</span></template>
|
<template #header>
|
||||||
|
<el-tooltip placement="top" effect="dark">
|
||||||
|
<div slot="content">
|
||||||
|
实际支付金额/理论支付金额:<br/>
|
||||||
|
1. 实际支付金额是按照矿机实际算力计算支付金额<br/>
|
||||||
|
2. 理论支付金额是卖家定义出售价格
|
||||||
|
</div>
|
||||||
|
<span style="display:inline-flex;align-items:center;gap:6px;">
|
||||||
|
<i class="el-icon-question" style="color:#909399;" aria-label="说明" role="img"></i>
|
||||||
|
已支付金额(USDT)
|
||||||
|
</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<span class="value strong">{{ (scope.row && scope.row.payAmount) != null ? scope.row.payAmount : '—' }}</span>
|
||||||
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="待支付金额(USDT)" min-width="140">
|
<el-table-column label="待支付金额(USDT)" min-width="140">
|
||||||
<template #default="scope"><span class="value strong">{{ (scope.row && scope.row.noPayAmount) != null ? scope.row.noPayAmount : '—' }}</span></template>
|
<template #default="scope"><span class="value strong">{{ (scope.row && scope.row.noPayAmount) != null ? scope.row.noPayAmount : '—' }}</span></template>
|
||||||
@@ -65,7 +80,18 @@
|
|||||||
<el-dialog :visible.sync="dialogVisible" width="520px" title="请扫码支付">
|
<el-dialog :visible.sync="dialogVisible" width="520px" title="请扫码支付">
|
||||||
<div style="text-align:left; margin-bottom:12px; color:#666;">
|
<div style="text-align:left; margin-bottom:12px; color:#666;">
|
||||||
<div style="margin-bottom:6px;">总金额(USDT):<b>{{ paymentDialog.totalPrice }}</b></div>
|
<div style="margin-bottom:6px;">总金额(USDT):<b>{{ paymentDialog.totalPrice }}</b></div>
|
||||||
<div style="margin-bottom:6px;">已支付金额(USDT):<b class="value strong">{{ paymentDialog.payAmount }}</b></div>
|
<div style="margin-bottom:6px;display:flex;align-items:center;gap:6px;">
|
||||||
|
<el-tooltip placement="top" effect="dark">
|
||||||
|
<div slot="content">
|
||||||
|
实际支付金额/理论支付金额:<br/>
|
||||||
|
1. 实际支付金额是按照矿机实际算力计算支付金额<br/>
|
||||||
|
2. 理论支付金额是卖家定义出售价格
|
||||||
|
</div>
|
||||||
|
<i class="el-icon-question" style="color:#909399;" aria-label="说明" role="img"></i>
|
||||||
|
</el-tooltip>
|
||||||
|
<span>已支付金额(USDT):</span>
|
||||||
|
<b class="value strong">{{ paymentDialog.payAmount }}</b>
|
||||||
|
</div>
|
||||||
<div style="margin-bottom:6px;">待支付金额(USDT):<b class="value strong">{{ paymentDialog.noPayAmount }}</b></div>
|
<div style="margin-bottom:6px;">待支付金额(USDT):<b class="value strong">{{ paymentDialog.noPayAmount }}</b></div>
|
||||||
<!-- <div style="word-break:break-all;">收款地址:<code>{{ orderDialog.address }}</code></div> -->
|
<!-- <div style="word-break:break-all;">收款地址:<code>{{ orderDialog.address }}</code></div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<div v-for="(row, idx) in rechargeRows" :key="getRowKey(row, idx)" class="record-item" :class="statusClass(row.status)" @click="toggleExpand('recharge', row, idx)">
|
<div v-for="(row, idx) in rechargeRows" :key="getRowKey(row, idx)" class="record-item" :class="statusClass(row.status)" @click="toggleExpand('recharge', row, idx)">
|
||||||
<div class="item-main">
|
<div class="item-main">
|
||||||
<div class="item-left">
|
<div class="item-left">
|
||||||
<div class="amount">+ {{ formatTrunc(row.amount, 2) }} {{ row.fromSymbol || 'USDT' }}</div>
|
<div class="amount">+ {{ formatDec6(row.amount) }} {{ (row.fromSymbol || 'USDT').toUpperCase() }}</div>
|
||||||
<div class="chain">{{ formatChain(row.fromChain) }}</div>
|
<div class="chain">{{ formatChain(row.fromChain) }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-right">
|
<div class="item-right">
|
||||||
@@ -23,8 +23,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-show="isExpanded('recharge', row, idx)" class="expand-panel">
|
<div v-show="isExpanded('recharge', row, idx)" class="expand-panel">
|
||||||
<div class="expand-grid">
|
<div class="expand-grid">
|
||||||
<div class="expand-item"><span class="label">充值地址</span><span class="value mono-ellipsis" :title="row.fromAddress">{{ row.fromAddress }}</span></div>
|
<div class="expand-item">
|
||||||
<div class="expand-item" v-if="row.txHash"><span class="label">交易哈希</span><span class="value mono-ellipsis" :title="row.txHash">{{ row.txHash }}</span></div>
|
<span class="label">充值地址</span>
|
||||||
|
<div class="value value-row">
|
||||||
|
<span class="mono-ellipsis" :title="row.fromAddress">{{ row.fromAddress }}</span>
|
||||||
|
<el-button type="text" size="mini" icon="el-icon-document-copy" @click.stop="handleCopy(row.fromAddress, '充值地址')">复制</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="expand-item" v-if="row.txHash">
|
||||||
|
<span class="label">交易哈希</span>
|
||||||
|
<div class="value value-row">
|
||||||
|
<span class="mono-ellipsis" :title="row.txHash">{{ row.txHash }}</span>
|
||||||
|
<el-button type="text" size="mini" icon="el-icon-document-copy" @click.stop="handleCopy(row.txHash, '交易哈希')">复制</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -42,7 +54,7 @@
|
|||||||
<div v-for="(row, idx) in withdrawRows" :key="getRowKey(row, idx)" class="record-item" :class="statusClass(row.status)" @click="toggleExpand('withdraw', row, idx)">
|
<div v-for="(row, idx) in withdrawRows" :key="getRowKey(row, idx)" class="record-item" :class="statusClass(row.status)" @click="toggleExpand('withdraw', row, idx)">
|
||||||
<div class="item-main">
|
<div class="item-main">
|
||||||
<div class="item-left">
|
<div class="item-left">
|
||||||
<div class="amount">- {{ formatTrunc(row.amount, 2) }} {{ row.toSymbol || 'USDT' }}</div>
|
<div class="amount">- {{ formatDec6(row.amount) }} {{ (row.toSymbol || 'USDT').toUpperCase() }}</div>
|
||||||
<div class="chain">{{ formatChain(row.toChain) }}</div>
|
<div class="chain">{{ formatChain(row.toChain) }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-right">
|
<div class="item-right">
|
||||||
@@ -52,8 +64,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-show="isExpanded('withdraw', row, idx)" class="expand-panel">
|
<div v-show="isExpanded('withdraw', row, idx)" class="expand-panel">
|
||||||
<div class="expand-grid">
|
<div class="expand-grid">
|
||||||
<div class="expand-item"><span class="label">收款地址</span><span class="value mono-ellipsis" :title="row.toAddress">{{ row.toAddress }}</span></div>
|
<div class="expand-item">
|
||||||
<div class="expand-item" v-if="row.txHash"><span class="label">交易哈希</span><span class="value mono-ellipsis" :title="row.txHash">{{ row.txHash }}</span></div>
|
<span class="label">收款地址</span>
|
||||||
|
<div class="value value-row">
|
||||||
|
<span class="mono-ellipsis" :title="row.toAddress">{{ row.toAddress }}</span>
|
||||||
|
<el-button type="text" size="mini" icon="el-icon-document-copy" @click.stop="handleCopy(row.toAddress, '收款地址')">复制</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="expand-item" v-if="row.txHash">
|
||||||
|
<span class="label">交易哈希</span>
|
||||||
|
<div class="value value-row">
|
||||||
|
<span class="mono-ellipsis" :title="row.txHash">{{ row.txHash }}</span>
|
||||||
|
<el-button type="text" size="mini" icon="el-icon-document-copy" @click.stop="handleCopy(row.txHash, '交易哈希')">复制</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -71,7 +95,7 @@
|
|||||||
<div v-for="(row, idx) in consumeRows" :key="getRowKey(row, idx)" class="record-item" :class="statusClass(row.status)" @click="toggleExpand('consume', row, idx)">
|
<div v-for="(row, idx) in consumeRows" :key="getRowKey(row, idx)" class="record-item" :class="statusClass(row.status)" @click="toggleExpand('consume', row, idx)">
|
||||||
<div class="item-main">
|
<div class="item-main">
|
||||||
<div class="item-left">
|
<div class="item-left">
|
||||||
<div class="amount">- {{ formatTrunc(row.realAmount, 2) }} {{ (row.fromSymbol || 'USDT').toUpperCase() }}</div>
|
<div class="amount">- {{ formatDec6(row.realAmount) }} {{ (row.fromSymbol || 'USDT').toUpperCase() }}</div>
|
||||||
<div class="chain">{{ formatChain(row.fromChain) }}</div>
|
<div class="chain">{{ formatChain(row.fromChain) }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-right">
|
<div class="item-right">
|
||||||
@@ -138,7 +162,7 @@ export default {
|
|||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// createTime: '2024-01-15 14:30:25',
|
// createTime: '2024-01-15 14:30:25',
|
||||||
// amount: 100,
|
// amount: 100.656578965,
|
||||||
// fromAddress: 'djdddksfhsfj',
|
// fromAddress: 'djdddksfhsfj',
|
||||||
// fromChain: 'tron',
|
// fromChain: 'tron',
|
||||||
// fromSymbol: 'USDT',
|
// fromSymbol: 'USDT',
|
||||||
@@ -345,9 +369,16 @@ export default {
|
|||||||
getPayStatusType(s) { return ({ 0: 'danger', 1: 'success', 2: 'warning', 3: 'danger' })[s] || 'info' },
|
getPayStatusType(s) { return ({ 0: 'danger', 1: 'success', 2: 'warning', 3: 'danger' })[s] || 'info' },
|
||||||
getPayStatusText(s) { return ({ 0: '支付失败', 1: '支付成功', 2: '待校验', 3: '证书校验失败' })[s] || '未知' },
|
getPayStatusText(s) { return ({ 0: '支付失败', 1: '支付成功', 2: '待校验', 3: '证书校验失败' })[s] || '未知' },
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将链名称标准化为大写简称
|
||||||
|
* @param {string} chain - 后端返回的链标识,如 tron/eth/ethereum/bsc/polygon
|
||||||
|
* @returns {string} 大写显示,如 TRON/ETH/BSC/POLYGON
|
||||||
|
*/
|
||||||
formatChain(chain) {
|
formatChain(chain) {
|
||||||
const map = { tron: 'Tron (TRC20)', ethereum: 'Ethereum (ERC20)', bsc: 'BSC (BEP20)', polygon: 'Polygon (MATIC)' }
|
if (!chain) return ''
|
||||||
return map[chain] || chain
|
const key = String(chain).toLowerCase()
|
||||||
|
const map = { tron: 'TRON', trx: 'TRON', eth: 'ETH', ethereum: 'ETH', bsc: 'BSC', polygon: 'POLYGON', matic: 'POLYGON' }
|
||||||
|
return (map[key] || String(chain)).toUpperCase()
|
||||||
},
|
},
|
||||||
formatFullTime(time) { if (!time) return ''; try { return new Date(time).toLocaleString('zh-CN') } catch (e) { return String(time) } },
|
formatFullTime(time) { if (!time) return ''; try { return new Date(time).toLocaleString('zh-CN') } catch (e) { return String(time) } },
|
||||||
formatTime(time) { return this.formatFullTime(time) },
|
formatTime(time) { return this.formatFullTime(time) },
|
||||||
@@ -363,6 +394,27 @@ export default {
|
|||||||
const padded = decPart.padEnd(d, '0')
|
const padded = decPart.padEnd(d, '0')
|
||||||
return `${intPart}.${padded}`
|
return `${intPart}.${padded}`
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 金额显示:保留最多6位小数,直接截断不四舍五入;不补尾随0;始终返回非负字符串
|
||||||
|
* @param {number|string} value
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
formatDec6(value) {
|
||||||
|
if (value === null || value === undefined || value === '') return '0'
|
||||||
|
let s = String(value)
|
||||||
|
// 展开科学计数法为普通小数,避免 1e-7 之类展示
|
||||||
|
if (/e/i.test(s)) {
|
||||||
|
const n = Number(value)
|
||||||
|
if (!Number.isFinite(n)) return '0'
|
||||||
|
s = n.toFixed(20).replace(/\.0+$/, '').replace(/(\.\d*?)0+$/, '$1')
|
||||||
|
}
|
||||||
|
const m = s.match(/^(-?)(\d+)(?:\.(\d+))?$/)
|
||||||
|
if (!m) return s
|
||||||
|
let intPart = m[2]
|
||||||
|
let decPart = m[3] || ''
|
||||||
|
if (decPart.length > 6) decPart = decPart.slice(0, 6)
|
||||||
|
return decPart ? `${intPart}.${decPart}` : intPart
|
||||||
|
},
|
||||||
handleSizeChange(val) {
|
handleSizeChange(val) {
|
||||||
console.log(`每页 ${val} 条`);
|
console.log(`每页 ${val} 条`);
|
||||||
this.pagination.pageSize = val;
|
this.pagination.pageSize = val;
|
||||||
@@ -376,6 +428,33 @@ export default {
|
|||||||
this.loadList();
|
this.loadList();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制文本到剪贴板
|
||||||
|
* @param {string} text - 需要复制的内容
|
||||||
|
* @param {string} [label] - 语义标签,用于提示文案
|
||||||
|
*/
|
||||||
|
async handleCopy(text, label = '内容') {
|
||||||
|
try {
|
||||||
|
const value = String(text || '')
|
||||||
|
if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
await navigator.clipboard.writeText(value)
|
||||||
|
} else {
|
||||||
|
const ta = document.createElement('textarea')
|
||||||
|
ta.value = value
|
||||||
|
ta.style.position = 'fixed'
|
||||||
|
ta.style.left = '-9999px'
|
||||||
|
document.body.appendChild(ta)
|
||||||
|
ta.focus()
|
||||||
|
ta.select()
|
||||||
|
document.execCommand('copy')
|
||||||
|
document.body.removeChild(ta)
|
||||||
|
}
|
||||||
|
this.$message.success(`${label}已复制`)
|
||||||
|
} catch (e) {
|
||||||
|
this.$message.error('复制失败,请手动选择复制')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tab 名称转状态码
|
* Tab 名称转状态码
|
||||||
* @param {string} tabName - 'recharge' | 'withdraw' | 'consume'
|
* @param {string} tabName - 'recharge' | 'withdraw' | 'consume'
|
||||||
@@ -434,6 +513,7 @@ export default {
|
|||||||
.expand-item { display: grid; grid-template-columns: 80px 1fr; gap: 6px; align-items: center; }
|
.expand-item { display: grid; grid-template-columns: 80px 1fr; gap: 6px; align-items: center; }
|
||||||
.label { color: #666; font-size: 13px; text-align: right; }
|
.label { color: #666; font-size: 13px; text-align: right; }
|
||||||
.value { color: #333; font-size: 13px; text-align: left; }
|
.value { color: #333; font-size: 13px; text-align: left; }
|
||||||
|
.value-row { display: inline-flex; align-items: center; gap: 6px; }
|
||||||
.mono { font-family: "Monaco", "Menlo", monospace; }
|
.mono { font-family: "Monaco", "Menlo", monospace; }
|
||||||
.mono-ellipsis { font-family: "Monaco", "Menlo", monospace; max-width: 480px; display: inline-block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.mono-ellipsis { font-family: "Monaco", "Menlo", monospace; max-width: 480px; display: inline-block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.empty { text-align: center; color: #999; padding: 20px 0; }
|
.empty { text-align: center; color: #999; padding: 20px 0; }
|
||||||
|
|||||||
@@ -38,8 +38,7 @@
|
|||||||
v-for="item in displayedLinks"
|
v-for="item in displayedLinks"
|
||||||
:key="item.to"
|
:key="item.to"
|
||||||
:to="item.to"
|
:to="item.to"
|
||||||
class="side-link"
|
:class="['side-link', isActiveLink(item.to) ? 'active' : '']"
|
||||||
active-class="active"
|
|
||||||
>{{ item.label }}</router-link>
|
>{{ item.label }}</router-link>
|
||||||
</nav>
|
</nav>
|
||||||
</aside>
|
</aside>
|
||||||
@@ -104,13 +103,16 @@ export default {
|
|||||||
if (raw == null) return null
|
if (raw == null) return null
|
||||||
try { return JSON.parse(raw) } catch (e) { return raw }
|
try { return JSON.parse(raw) } catch (e) { return raw }
|
||||||
}
|
}
|
||||||
const val = getVal('userName') || getVal('userEmail') || ''
|
const val =getVal('leasEmail') || ''
|
||||||
this.userEmail = typeof val === 'string' ? val : String(val)
|
this.userEmail = typeof val === 'string' ? val : String(val)
|
||||||
// 恢复上次选择的导航分组(如无则默认 seller)
|
// 恢复上次选择的导航分组(如无则默认 seller)
|
||||||
const savedRole = getVal('accountActiveRole')
|
const savedRole = getVal('accountActiveRole')
|
||||||
if (savedRole === 'buyer' || savedRole === 'seller') {
|
if (savedRole === 'buyer' || savedRole === 'seller') {
|
||||||
this.activeRole = savedRole
|
this.activeRole = savedRole
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// 根据当前路由自动匹配分组,确保左侧导航高亮正确
|
||||||
|
this.setActiveRoleByRoute()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
/**
|
||||||
@@ -122,8 +124,78 @@ export default {
|
|||||||
if (role !== 'buyer' && role !== 'seller') return
|
if (role !== 'buyer' && role !== 'seller') return
|
||||||
this.activeRole = role
|
this.activeRole = role
|
||||||
try { localStorage.setItem('accountActiveRole', JSON.stringify(role)) } catch (e) {}
|
try { localStorage.setItem('accountActiveRole', JSON.stringify(role)) } catch (e) {}
|
||||||
|
// 切换分组后,立即跳转到该分组的第一个导航页面
|
||||||
|
try {
|
||||||
|
const firstPath = role === 'buyer'
|
||||||
|
? (this.buyerLinks && this.buyerLinks[0] && this.buyerLinks[0].to)
|
||||||
|
: (this.sellerLinks && this.sellerLinks[0] && this.sellerLinks[0].to)
|
||||||
|
if (firstPath && this.$route && this.$route.path !== firstPath) {
|
||||||
|
this.$router.push(firstPath)
|
||||||
|
}
|
||||||
|
} catch (e) { /* noop */ }
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 根据当前路由自动选择导航分组,保证进入“我的店铺”等卖家页面时左侧高亮正确
|
||||||
|
*/
|
||||||
|
setActiveRoleByRoute() {
|
||||||
|
const path = (this.$route && this.$route.path) || ''
|
||||||
|
// 买家前缀优先匹配,确保“已购详情”等页面归属买家侧
|
||||||
|
const buyerPrefixes = [
|
||||||
|
'/account/wallet',
|
||||||
|
'/account/purchased',
|
||||||
|
'/account/purchased-detail',
|
||||||
|
'/account/orders',
|
||||||
|
'/account/funds-flow'
|
||||||
|
]
|
||||||
|
const sellerPrefixes = [
|
||||||
|
'/account/shops',
|
||||||
|
'/account/shop-new',
|
||||||
|
'/account/product-new',
|
||||||
|
'/account/products',
|
||||||
|
'/account/product-detail',
|
||||||
|
'/account/product-machine-add',
|
||||||
|
'/account/seller-orders',
|
||||||
|
'/account/order-detail',
|
||||||
|
'/account/receipt-record',
|
||||||
|
'/account/shop-config'
|
||||||
|
]
|
||||||
|
const shouldBuyer = buyerPrefixes.some(p => path.indexOf(p) === 0)
|
||||||
|
const shouldSeller = sellerPrefixes.some(p => path.indexOf(p) === 0)
|
||||||
|
const role = shouldBuyer ? 'buyer' : (shouldSeller ? 'seller' : this.activeRole)
|
||||||
|
if (this.activeRole !== role) {
|
||||||
|
this.activeRole = role
|
||||||
|
try { localStorage.setItem('accountActiveRole', JSON.stringify(role)) } catch (e) {}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 判断左侧导航项是否高亮
|
||||||
|
* - 普通路径完全匹配
|
||||||
|
* - “已售出订单”需同时匹配详情页 /account/order-detail/:id
|
||||||
|
*/
|
||||||
|
isActiveLink(pathLike) {
|
||||||
|
const current = (this.$route && this.$route.path) || ''
|
||||||
|
if (!pathLike) return false
|
||||||
|
// 列表-详情联动高亮映射
|
||||||
|
const map = {
|
||||||
|
'/account/seller-orders': ['/account/seller-orders', '/account/order-detail'],
|
||||||
|
'/account/products': ['/account/products', '/account/product-detail'],
|
||||||
|
'/account/purchased': ['/account/purchased', '/account/purchased-detail']
|
||||||
|
}
|
||||||
|
const prefixes = map[pathLike]
|
||||||
|
if (Array.isArray(prefixes)) {
|
||||||
|
return prefixes.some(p => current.indexOf(p) === 0)
|
||||||
|
}
|
||||||
|
return current.indexOf(pathLike) === 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'$route.path': {
|
||||||
|
immediate: true,
|
||||||
|
handler() {
|
||||||
|
this.setActiveRoleByRoute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -172,6 +244,7 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
|
margin-top: 18px;
|
||||||
}
|
}
|
||||||
.role-button {
|
.role-button {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
|
|||||||
@@ -134,17 +134,17 @@
|
|||||||
<el-dialog title="修改配置" :visible.sync="visibleConfigEdit" width="560px">
|
<el-dialog title="修改配置" :visible.sync="visibleConfigEdit" width="560px">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="label">支付链</label>
|
<label class="label">支付链</label>
|
||||||
<el-select v-model="configForm.chain" placeholder="请选择链">
|
<el-input v-model="configForm.chainLabel" placeholder="-" disabled />
|
||||||
<el-option v-for="c in chainOptions" :key="c.value" :value="c.value" :label="c.label" />
|
|
||||||
</el-select>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="label">支付币种</label>
|
<label class="label">支付币种</label>
|
||||||
<el-select
|
<el-select
|
||||||
class="input"
|
class="input"
|
||||||
size="middle"
|
size="middle"
|
||||||
ref="screen"
|
v-model="configForm.payCoins"
|
||||||
v-model="configForm.payCoin"
|
multiple
|
||||||
|
collapse-tags
|
||||||
|
filterable
|
||||||
placeholder="请选择币种"
|
placeholder="请选择币种"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
@@ -152,20 +152,22 @@
|
|||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
>
|
/>
|
||||||
<div style="display: flex; align-items: center">
|
|
||||||
<img v-if="item.imgUrl" :src="item.imgUrl" style="float: left; width: 20px" />
|
|
||||||
<span style="float: left; margin-left: 5px">{{ item.label }}</span>
|
|
||||||
</div>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="label">币种类型</label>
|
<label class="label">已选择币种</label>
|
||||||
<el-radio-group v-model="configForm.payType">
|
<div class="selected-coin-list">
|
||||||
<el-radio :label="0">虚拟币</el-radio>
|
<el-tag
|
||||||
<el-radio :label="1">稳定币</el-radio>
|
v-for="c in selectedCoinLabels"
|
||||||
</el-radio-group>
|
:key="c"
|
||||||
|
type="warning"
|
||||||
|
effect="light"
|
||||||
|
closable
|
||||||
|
@close="removeSelectedCoin(c)"
|
||||||
|
>{{ c }}</el-tag>
|
||||||
|
<span v-if="!selectedCoinLabels.length" style="color:#c0c4cc">未选择</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<label class="label">钱包地址</label>
|
<label class="label">钱包地址</label>
|
||||||
@@ -173,7 +175,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<span slot="footer" class="dialog-footer">
|
<span slot="footer" class="dialog-footer">
|
||||||
<el-button @click="visibleConfigEdit=false">取消</el-button>
|
<el-button @click="visibleConfigEdit=false">取消</el-button>
|
||||||
<el-button type="primary" @click="submitConfigEdit">保存</el-button>
|
<el-button type="primary" @click="submitConfigEdit">确认修改</el-button>
|
||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -181,7 +183,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getMyShop, updateShop, deleteShop, queryShop, closeShop ,updateShopConfig,deleteShopConfig} from '@/api/shops'
|
import { getMyShop, updateShop, deleteShop, queryShop, closeShop ,updateShopConfig,deleteShopConfig,getChainAndCoin} from '@/api/shops'
|
||||||
|
|
||||||
import { coinList } from '@/utils/coinList'
|
import { coinList } from '@/utils/coinList'
|
||||||
import { getShopConfig } from '@/api/wallet'
|
import { getShopConfig } from '@/api/wallet'
|
||||||
@@ -206,9 +208,10 @@ export default {
|
|||||||
// 店铺配置列表
|
// 店铺配置列表
|
||||||
shopConfigs: [],
|
shopConfigs: [],
|
||||||
visibleConfigEdit: false,
|
visibleConfigEdit: false,
|
||||||
configForm: { id: '', chain: '', payAddress: '', payCoin: '', payType: 0 },
|
configForm: { id: '', chainLabel: '', chainValue: '', payAddress: '', payCoins: [], payCoin: '' },
|
||||||
productOptions: [],
|
productOptions: [],
|
||||||
coinOptions: coinList || [],
|
coinOptions: coinList || [],
|
||||||
|
editCoinOptionsApi: [],
|
||||||
// 支付链选项(可与后端接口对齐后替换为动态)
|
// 支付链选项(可与后端接口对齐后替换为动态)
|
||||||
chainOptions: [
|
chainOptions: [
|
||||||
{ label: 'Tron (TRC20)', value: 'tron' },
|
{ label: 'Tron (TRC20)', value: 'tron' },
|
||||||
@@ -244,14 +247,12 @@ export default {
|
|||||||
* 弹窗可选币种:稳定币/虚拟币分流
|
* 弹窗可选币种:稳定币/虚拟币分流
|
||||||
*/
|
*/
|
||||||
editCoinOptions() {
|
editCoinOptions() {
|
||||||
if (Number(this.configForm.payType) === 1) {
|
if (Array.isArray(this.editCoinOptionsApi) && this.editCoinOptionsApi.length) return this.editCoinOptionsApi
|
||||||
return [
|
|
||||||
{ label: 'USDT', value: 'usdt' },
|
|
||||||
{ label: 'USDC', value: 'usdc' },
|
|
||||||
{ label: 'BUSD', value: 'busd' },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
return this.coinOptions
|
return this.coinOptions
|
||||||
|
},
|
||||||
|
selectedCoinLabels() {
|
||||||
|
const map = new Map((this.editCoinOptions || []).map(o => [String(o.value), String(o.label).toUpperCase()]))
|
||||||
|
return (this.configForm.payCoins || []).map(v => map.get(String(v)) || String(v).toUpperCase())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@@ -338,8 +339,6 @@ export default {
|
|||||||
this.$message.success('保存成功')
|
this.$message.success('保存成功')
|
||||||
this.visibleConfigEdit = false
|
this.visibleConfigEdit = false
|
||||||
this.fetchShopConfigs(this.shop.id)
|
this.fetchShopConfigs(this.shop.id)
|
||||||
} else {
|
|
||||||
this.$message.error(res && res.msg ? res.msg : '保存失败')
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async deleteShopConfig(params) {
|
async deleteShopConfig(params) {
|
||||||
@@ -349,16 +348,41 @@ export default {
|
|||||||
this.fetchShopConfigs(this.shop.id)
|
this.fetchShopConfigs(this.shop.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleEditConfig(row) {
|
async handleEditConfig(row) {
|
||||||
|
try {
|
||||||
|
const res = await getChainAndCoin({ id: row.id })
|
||||||
|
if (res && (res.code === 0 || res.code === 200) && res.data) {
|
||||||
|
const d = res.data || {}
|
||||||
|
const children = Array.isArray(d.children) ? d.children : []
|
||||||
|
this.editCoinOptionsApi = children.map(c => ({ label: c.label, value: c.value }))
|
||||||
|
const preSelected = children.filter(c => Number(c.hasBind) === 1).map(c => c.value)
|
||||||
this.configForm = {
|
this.configForm = {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
chain: row.chain || '',
|
chainLabel: d.label || '',
|
||||||
payCoin: row.payCoin || '',
|
chainValue: d.value || '',
|
||||||
payType: typeof row.payType === 'number' ? row.payType : Number(row.payType || 0),
|
payAddress: d.address || '',
|
||||||
|
payCoins: preSelected,
|
||||||
|
payCoin: preSelected.join(',')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 回退:使用行内已有数据
|
||||||
|
this.editCoinOptionsApi = []
|
||||||
|
const chainLabel = row.chain || ''
|
||||||
|
const payCoinStr = String(row.payCoin || '')
|
||||||
|
const payCoins = payCoinStr ? payCoinStr.split(',') : []
|
||||||
|
this.configForm = {
|
||||||
|
id: row.id,
|
||||||
|
chainLabel,
|
||||||
|
chainValue: row.chain || '',
|
||||||
payAddress: row.payAddress || '',
|
payAddress: row.payAddress || '',
|
||||||
|
payCoins,
|
||||||
|
payCoin: payCoins.join(',')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.visibleConfigEdit = true
|
this.visibleConfigEdit = true
|
||||||
|
} catch (e) {
|
||||||
|
this.visibleConfigEdit = true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async handleDeleteConfig(row) {
|
async handleDeleteConfig(row) {
|
||||||
this.deleteShopConfig({id:row.id})
|
this.deleteShopConfig({id:row.id})
|
||||||
@@ -366,11 +390,11 @@ export default {
|
|||||||
|
|
||||||
submitConfigEdit() {
|
submitConfigEdit() {
|
||||||
// 基础校验
|
// 基础校验
|
||||||
if (!this.configForm.chain) {
|
if (!this.configForm.chainLabel && !this.configForm.chainValue) {
|
||||||
this.$message.warning('请选择支付链')
|
this.$message.warning('请选择支付链')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!this.configForm.payCoin) {
|
if (!this.configForm.payCoins || this.configForm.payCoins.length === 0) {
|
||||||
this.$message.warning('请选择支付币种')
|
this.$message.warning('请选择支付币种')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -379,10 +403,21 @@ export default {
|
|||||||
this.$message.warning('请输入钱包地址')
|
this.$message.warning('请输入钱包地址')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { productId, ...rest } = this.configForm
|
const payload = {
|
||||||
const payload = { ...rest, payType: Number(this.configForm.payType || 0) }
|
id: this.configForm.id,
|
||||||
|
chain: this.configForm.chainValue || this.configForm.chainLabel,
|
||||||
|
payCoin: (this.configForm.payCoins || []).join(','),
|
||||||
|
payAddress: this.configForm.payAddress
|
||||||
|
}
|
||||||
this.updateShopConfig(payload)
|
this.updateShopConfig(payload)
|
||||||
},
|
},
|
||||||
|
removeSelectedCoin(labelUpper) {
|
||||||
|
const label = String(labelUpper || '').toLowerCase()
|
||||||
|
const map = new Map((this.editCoinOptions || []).map(o => [String(o.label).toLowerCase(), String(o.value)]))
|
||||||
|
const value = map.get(label)
|
||||||
|
if (!value) return
|
||||||
|
this.configForm.payCoins = (this.configForm.payCoins || []).filter(v => String(v) !== String(value))
|
||||||
|
},
|
||||||
async handleOpenEdit() {
|
async handleOpenEdit() {
|
||||||
try {
|
try {
|
||||||
// 先打开弹窗,提供更快的视觉反馈
|
// 先打开弹窗,提供更快的视觉反馈
|
||||||
@@ -627,5 +662,9 @@ export default {
|
|||||||
.el-dialog__footer {
|
.el-dialog__footer {
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 已选择币种 - 靠左对齐且换行友好 */
|
||||||
|
.selected-coin-list { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-start; }
|
||||||
|
.selected-coin-list .el-tag { margin-right: 0; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<el-card class="section">
|
<el-card class="section">
|
||||||
<div class="row"><span class="label">订单ID:</span><span class="value mono">{{ order.id || '—' }}</span></div>
|
<div class="row"><span class="label">订单ID:</span><span class="value mono">{{ order.id || '—' }}</span></div>
|
||||||
<div class="row"><span class="label">订单号:</span><span class="value mono">{{ order.orderNumber || '—' }}</span></div>
|
<div class="row"><span class="label">订单号:</span><span class="value mono">{{ order.orderNumber || '—' }}</span></div>
|
||||||
<div class="row"><span class="label">状态:</span><span class="value">{{ order.status }}</span></div>
|
<div class="row"><span class="label">状态:</span><span class="value">{{ getOrderStatusText(order.status) }}</span></div>
|
||||||
<div class="row"><span class="label">金额(USDT):</span><span class="value strong">{{ order.totalPrice }}</span></div>
|
<div class="row"><span class="label">金额(USDT):</span><span class="value strong">{{ order.totalPrice }}</span></div>
|
||||||
<div class="row"><span class="label">创建时间:</span><span class="value">{{ formatDateTime(order.createTime) }}</span></div>
|
<div class="row"><span class="label">创建时间:</span><span class="value">{{ formatDateTime(order.createTime) }}</span></div>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -72,8 +72,17 @@ export default {
|
|||||||
} finally {
|
} finally {
|
||||||
this.loading = false
|
this.loading = false
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
,
|
/**
|
||||||
|
* 订单状态文案映射
|
||||||
|
* 7: 进行中;8: 已完成;其他:原样返回
|
||||||
|
*/
|
||||||
|
getOrderStatusText(value) {
|
||||||
|
const n = Number(value)
|
||||||
|
if (n === 7) return '进行中'
|
||||||
|
if (n === 8) return '已完成'
|
||||||
|
return String(value == null ? '' : value)
|
||||||
|
},
|
||||||
formatDateTime(value) {
|
formatDateTime(value) {
|
||||||
if (!value) return '—'
|
if (!value) return '—'
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -916,7 +916,13 @@ export default {
|
|||||||
|
|
||||||
const res = await addSingleOrBatchMachine(payload)
|
const res = await addSingleOrBatchMachine(payload)
|
||||||
if (res && (res.code === 0 || res.code === 200)) {
|
if (res && (res.code === 0 || res.code === 200)) {
|
||||||
this.$message.success('添加成功')
|
|
||||||
|
this.$message({
|
||||||
|
message: '添加成功',
|
||||||
|
duration: 3000,
|
||||||
|
showClose: true,
|
||||||
|
type: 'success'
|
||||||
|
})
|
||||||
this.confirmVisible = false
|
this.confirmVisible = false
|
||||||
this.$router.back()
|
this.$router.back()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,11 +190,24 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
this.userEmail=JSON.parse(localStorage.getItem('userEmail'))
|
this.userEmail=JSON.parse(localStorage.getItem('leasEmail'))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if ( !this.userEmail) {
|
||||||
|
this.$alert('登录信息异常,请重新返回 m2poll 矿池进入该系统', '提示', {
|
||||||
|
confirmButtonText: '确认',
|
||||||
|
center: true,
|
||||||
|
closeOnClickModal: false,
|
||||||
|
closeOnPressEscape: false,
|
||||||
|
showClose: false,
|
||||||
|
callback: () => {
|
||||||
|
window.location.href = 'https://m2pool.com'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
const params = {
|
const params = {
|
||||||
pageNum: this.pagination.pageNum,
|
pageNum: this.pagination.pageNum,
|
||||||
pageSize: this.pagination.pageSize,
|
pageSize: this.pagination.pageSize,
|
||||||
|
|||||||
@@ -287,8 +287,9 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.receipt-page { padding: 4px; }
|
|
||||||
.card { background: #fff; border: 1px solid #eee; border-radius: 10px; padding: 12px; box-shadow: 0 4px 18px rgba(0,0,0,0.04); }
|
.receipt-page { margin: 0; box-sizing: border-box; overflow-x: hidden; }
|
||||||
|
.card { background: #fff; border: 1px solid #eee; border-radius: 10px; padding: 12px; box-shadow: 0 4px 18px rgba(0,0,0,0.04); overflow-x: auto; }
|
||||||
.card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
|
.card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
|
||||||
.card-title { margin: 0; font-size: 18px; font-weight: 700; color: #2c3e50; }
|
.card-title { margin: 0; font-size: 18px; font-weight: 700; color: #2c3e50; }
|
||||||
.card-actions { display: flex; align-items: center; gap: 8px; }
|
.card-actions { display: flex; align-items: center; gap: 8px; }
|
||||||
|
|||||||
@@ -3,16 +3,43 @@
|
|||||||
<h2 class="panel-title page-title">钱包绑定</h2>
|
<h2 class="panel-title page-title">钱包绑定</h2>
|
||||||
<div class="panel-body" v-loading="loading">
|
<div class="panel-body" v-loading="loading">
|
||||||
<el-form :model="form" label-width="120px" class="config-form">
|
<el-form :model="form" label-width="120px" class="config-form">
|
||||||
<el-form-item label="选择链">
|
<el-form-item label="选择链/币种">
|
||||||
<el-cascader style="width: 420px;" @change="handleChange" v-model="value" :options="options"> </el-cascader>
|
<el-cascader
|
||||||
|
style="width: 420px;"
|
||||||
|
v-model="value"
|
||||||
|
:options="options"
|
||||||
|
:props="cascaderProps"
|
||||||
|
:show-all-levels="false"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
@change="handleChange"
|
||||||
|
@expand-change="handleExpandChange"
|
||||||
|
>
|
||||||
|
<template slot-scope="{ node, data }">
|
||||||
|
<span class="custom-node" aria-label="cascader-item" tabindex="0" @click.stop="handleItemClick(node, data)">
|
||||||
|
<span class="node-label">{{ data.label }}</span>
|
||||||
|
<span v-if="node.isLeaf && node.checked" class="leaf-checked" aria-hidden="true">✓</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-cascader>
|
||||||
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="币种类型">
|
<el-form-item label="已选择币种">
|
||||||
<el-radio-group v-model="form.payType" class="radio-group">
|
<div class="selected-coins" aria-label="selected-coins" tabindex="0">
|
||||||
<!-- <el-radio :label="0">虚拟币</el-radio> -->
|
<el-tag
|
||||||
<el-radio :label="1">稳定币</el-radio>
|
v-for="coin in selectedCoins"
|
||||||
</el-radio-group>
|
:key="coin"
|
||||||
|
type="warning"
|
||||||
|
effect="light"
|
||||||
|
closable
|
||||||
|
disable-transitions
|
||||||
|
@close="handleRemoveSelectedCoin(coin)"
|
||||||
|
>
|
||||||
|
{{ coin }}
|
||||||
|
</el-tag>
|
||||||
|
<span v-if="selectedCoins.length === 0" class="placeholder">未选择</span>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
|
||||||
@@ -39,32 +66,15 @@
|
|||||||
import { getMyShop } from "@/api/shops";
|
import { getMyShop } from "@/api/shops";
|
||||||
import { getChainAndList, addWalletShopConfig } from "../../api/wallet";
|
import { getChainAndList, addWalletShopConfig } from "../../api/wallet";
|
||||||
|
|
||||||
// 币种集合
|
|
||||||
const VIRTUAL_COINS = [
|
|
||||||
"nexa",
|
|
||||||
"rxd",
|
|
||||||
"dgbo",
|
|
||||||
"dgbq",
|
|
||||||
"dgbs",
|
|
||||||
"alph",
|
|
||||||
"enx",
|
|
||||||
"grs",
|
|
||||||
"mona",
|
|
||||||
];
|
|
||||||
const STABLE_COINS = ["usdt", "usdc", "busd"];
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "AccountShopConfig",
|
name: "AccountShopConfig",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
VIRTUAL_COINS,
|
|
||||||
STABLE_COINS,
|
|
||||||
productOptions: [],
|
productOptions: [],
|
||||||
form: {
|
form: {
|
||||||
chain: "",
|
chain: "",
|
||||||
payAddress: "",
|
payAddress: "",
|
||||||
payCoin: "",
|
payCoin: "",
|
||||||
payType: 1, // 0 虚拟币 1 稳定币
|
|
||||||
|
|
||||||
},
|
},
|
||||||
shop: {
|
shop: {
|
||||||
@@ -75,7 +85,10 @@ export default {
|
|||||||
del: true,
|
del: true,
|
||||||
state: 0,
|
state: 0,
|
||||||
},
|
},
|
||||||
value: "",
|
// 级联多选值:形如 [[chain, coin], [chain, coin2]]
|
||||||
|
value: [],
|
||||||
|
currentChain: '',
|
||||||
|
cascaderProps: { multiple: true, checkStrictly: false, emitPath: true, value: 'value', label: 'label', children: 'children' },
|
||||||
options: [
|
options: [
|
||||||
// {
|
// {
|
||||||
// value: "Tron (TRC20)",
|
// value: "Tron (TRC20)",
|
||||||
@@ -110,6 +123,49 @@ export default {
|
|||||||
this.getChainAndList();
|
this.getChainAndList();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* 关闭标签 -> 移除对应币种
|
||||||
|
*/
|
||||||
|
handleRemoveSelectedCoin(coinUpper) {
|
||||||
|
const coin = String(coinUpper || '').toLowerCase()
|
||||||
|
const next = (this.value || []).filter(v => Array.isArray(v) && String(v[1]).toLowerCase() !== coin)
|
||||||
|
this.handleChange(next)
|
||||||
|
},
|
||||||
|
// 允许点击整行触发选择/展开,提升“可点文字即可选”的体验
|
||||||
|
handleItemClick(node, data) {
|
||||||
|
if (!node) return
|
||||||
|
if (node.isLeaf) {
|
||||||
|
// 叶子:切换选中
|
||||||
|
const path = node.path.map(n => n.value)
|
||||||
|
const chain = path[0]
|
||||||
|
const coin = path[1]
|
||||||
|
this.currentChain = String(chain || '')
|
||||||
|
let next = Array.isArray(this.value) ? this.value.slice() : []
|
||||||
|
// 始终以最后点击的链为准:如果链不同,清空旧链
|
||||||
|
const last = next.length ? next[next.length - 1] : null
|
||||||
|
const lastChain = Array.isArray(last) ? last[0] : null
|
||||||
|
if (lastChain && lastChain !== chain) next = []
|
||||||
|
const idx = next.findIndex(v => Array.isArray(v) && v[0] === chain && v[1] === coin)
|
||||||
|
if (idx >= 0) next.splice(idx, 1)
|
||||||
|
else next.push([chain, coin])
|
||||||
|
this.handleChange(next)
|
||||||
|
} else {
|
||||||
|
// 父级:以最后点击为准,清空旧链选择并切换到当前链
|
||||||
|
const chain = data && data.value
|
||||||
|
if (!node.expanded) node.expand()
|
||||||
|
if (chain) {
|
||||||
|
this.currentChain = String(chain)
|
||||||
|
this.value = []
|
||||||
|
this.form.chain = String(chain)
|
||||||
|
this.form.payCoin = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleExpandChange(nodes) {
|
||||||
|
// 记录当前展开的链,供 @change 过滤依据
|
||||||
|
const chain = Array.isArray(nodes) ? (nodes[0] || '') : ''
|
||||||
|
if (chain) this.currentChain = String(chain)
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 根据选择的链校验钱包地址格式(参考钱包页面规则)
|
* 根据选择的链校验钱包地址格式(参考钱包页面规则)
|
||||||
* - tron: 以 T 开头的 34 位字符
|
* - tron: 以 T 开头的 34 位字符
|
||||||
@@ -123,7 +179,9 @@ export default {
|
|||||||
|
|
||||||
if (c.includes('tron') || c === 'tron') {
|
if (c.includes('tron') || c === 'tron') {
|
||||||
const ok = /^T[A-Za-z1-9]{33}$/.test(addr)
|
const ok = /^T[A-Za-z1-9]{33}$/.test(addr)
|
||||||
return ok ? { ok: true } : { ok: false, message: '请输入正确的收款地址格式(TRON)' }
|
return ok
|
||||||
|
? { ok: true }
|
||||||
|
: { ok: false, message: '请输入正确的 TRON 地址:以 T 开头的 34 位字符' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -134,7 +192,9 @@ export default {
|
|||||||
c.includes('erc') || c.includes('bep')
|
c.includes('erc') || c.includes('bep')
|
||||||
) {
|
) {
|
||||||
const ok = /^0x[a-fA-F0-9]{40}$/.test(addr)
|
const ok = /^0x[a-fA-F0-9]{40}$/.test(addr)
|
||||||
return ok ? { ok: true } : { ok: false, message: '请输入正确的收款地址格式(EVM)' }
|
return ok
|
||||||
|
? { ok: true }
|
||||||
|
: { ok: false, message: '请输入正确的以太坊/EVM 兼容链地址:以 0x 开头 + 40 位十六进制' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr.length <= 10) {
|
if (addr.length <= 10) {
|
||||||
@@ -179,17 +239,28 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleChange(value) {
|
handleChange(value) {
|
||||||
console.log(value);
|
// 仅允许同一链下多选;无提示,始终以“最后一次点击”的链为准
|
||||||
|
const selections = Array.isArray(value) ? value : []
|
||||||
this.form.payCoin = value[1];
|
if (selections.length === 0) {
|
||||||
this.form.chain = value[0];
|
this.form.chain = ""
|
||||||
|
this.form.payCoin = ""
|
||||||
|
this.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const last = selections[selections.length - 1]
|
||||||
|
const lastChain = Array.isArray(last) ? last[0] : ''
|
||||||
|
const targetChain = this.currentChain || lastChain
|
||||||
|
const filtered = selections.filter(v => Array.isArray(v) && v[0] === targetChain)
|
||||||
|
this.value = filtered
|
||||||
|
this.form.chain = targetChain || ""
|
||||||
|
this.form.payCoin = filtered.map(v => v[1]).filter(Boolean).join(',')
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSave() {
|
handleSave() {
|
||||||
|
// 从多选值同步 chain 与 payCoin(英文逗号隔开)
|
||||||
this.form.chain =this.value[0]
|
const selections = Array.isArray(this.value) ? this.value : []
|
||||||
this.form.payCoin = this.value[1]
|
this.form.chain = selections.length ? (selections[0] && selections[0][0]) : ''
|
||||||
|
this.form.payCoin = selections.map(v => v && v[1]).filter(Boolean).join(',')
|
||||||
|
|
||||||
if (!this.form.chain) {
|
if (!this.form.chain) {
|
||||||
this.$message.warning("请选择链");
|
this.$message.warning("请选择链");
|
||||||
@@ -214,19 +285,25 @@ export default {
|
|||||||
this.FetchAddWalletShopConfig(this.form);
|
this.FetchAddWalletShopConfig(this.form);
|
||||||
},
|
},
|
||||||
handleReset() {
|
handleReset() {
|
||||||
this.form = { chain: "", payAddress: "", payCoin: "", payType: 0 };
|
this.form = { chain: "", payAddress: "", payCoin: "" };
|
||||||
|
this.value = []
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
// 根据币种类型动态展示可选币种
|
/**
|
||||||
coinOptions() {
|
* 已选择币种的可读展示(中文顿号分隔)
|
||||||
return this.form.payType === 1 ? STABLE_COINS : VIRTUAL_COINS;
|
*/
|
||||||
|
selectedCoinsDisplay() {
|
||||||
|
const arr = Array.isArray(this.value) ? this.value : []
|
||||||
|
const coins = arr.map(v => v && v[1]).filter(Boolean).map(s => String(s).toUpperCase())
|
||||||
|
return coins.join('、')
|
||||||
},
|
},
|
||||||
},
|
/**
|
||||||
watch: {
|
* 标签列表数据
|
||||||
"form.payType"(val) {
|
*/
|
||||||
// 切换类型时清空已选币种,避免类型与币种不匹配
|
selectedCoins() {
|
||||||
this.form.payCoin = "";
|
const arr = Array.isArray(this.value) ? this.value : []
|
||||||
|
return arr.map(v => v && v[1]).filter(Boolean).map(s => String(s).toUpperCase())
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -266,5 +343,15 @@ export default {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 自定义级联节点样式:叶子被选中时显示勾选 */
|
||||||
|
.custom-node { display: inline-flex; align-items: center; gap: 8px; }
|
||||||
|
.leaf-checked { color: #409EFF; font-weight: 700; }
|
||||||
|
.node-label { line-height: 20px; }
|
||||||
|
|
||||||
|
/* 已选择币种标签样式 */
|
||||||
|
.selected-coins { display: flex; flex-wrap: wrap; gap: 8px; min-height: 32px; align-items: center; margin-left: 79px;}
|
||||||
|
.selected-coins .el-tag { border-radius: 4px; }
|
||||||
|
.selected-coins .placeholder { color: #c0c4cc; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,14 @@
|
|||||||
<span class="balance-amount">{{ (w.walletBalance || w.balance || 0) }} {{ displaySymbol(w) }}</span>
|
<span class="balance-amount">{{ (w.walletBalance || w.balance || 0) }} {{ displaySymbol(w) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="balance-item">
|
<div class="balance-item">
|
||||||
|
<el-tooltip placement="top" effect="dark">
|
||||||
|
<div slot="content">
|
||||||
|
冻结金额不能使用或提现,以下情况会冻结钱包余额:<br/>
|
||||||
|
1. 下单机器后会冻结订单对应金额<br/>
|
||||||
|
2. 提交提现后,金额正在提现中
|
||||||
|
</div>
|
||||||
|
<i class="el-icon-question balance-tip-icon"></i>
|
||||||
|
</el-tooltip>
|
||||||
<span class="balance-label">冻结余额</span>
|
<span class="balance-label">冻结余额</span>
|
||||||
<span class="balance-amount frozen">{{ (w.blockedBalance || 0) }} {{ displaySymbol(w) }}</span>
|
<span class="balance-amount frozen">{{ (w.blockedBalance || 0) }} {{ displaySymbol(w) }}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -53,9 +61,16 @@
|
|||||||
<div class="transaction-info">
|
<div class="transaction-info">
|
||||||
<span class="transaction-type">{{ transaction.type }}</span>
|
<span class="transaction-type">{{ transaction.type }}</span>
|
||||||
<span class="transaction-time">{{ transaction.time }}</span>
|
<span class="transaction-time">{{ transaction.time }}</span>
|
||||||
|
<el-tag
|
||||||
|
size="mini"
|
||||||
|
class="transaction-status"
|
||||||
|
:type="transaction.statusTagType || 'info'"
|
||||||
|
>
|
||||||
|
{{ transaction.statusText || '-' }}
|
||||||
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
<div class="transaction-amount" :class="transaction.amount > 0 ? 'positive' : 'negative'">
|
<div class="transaction-amount" :class="transaction.amount > 0 ? 'positive' : 'negative'">
|
||||||
{{ transaction.amount > 0 ? '+' : '' }}{{ transaction.amount }} USDT
|
{{ transaction.amount > 0 ? '+' : '' }}{{ transaction.amountText }} USDT
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="recentTransactions.length === 0" class="empty-state">
|
<div v-if="recentTransactions.length === 0" class="empty-state">
|
||||||
@@ -136,8 +151,9 @@
|
|||||||
<el-dialog
|
<el-dialog
|
||||||
title="USDT提现"
|
title="USDT提现"
|
||||||
:visible.sync="withdrawDialogVisible"
|
:visible.sync="withdrawDialogVisible"
|
||||||
width="600px"
|
width="720px"
|
||||||
@close="resetWithdrawForm"
|
@close="resetWithdrawForm"
|
||||||
|
:close-on-click-modal="false" :close-on-press-escape="false"
|
||||||
>
|
>
|
||||||
<el-form :model="withdrawForm" :rules="withdrawRules" ref="withdrawForm" label-width="120px">
|
<el-form :model="withdrawForm" :rules="withdrawRules" ref="withdrawForm" label-width="120px">
|
||||||
<!-- 提现链(只读展示当前钱包链) -->
|
<!-- 提现链(只读展示当前钱包链) -->
|
||||||
@@ -170,12 +186,22 @@
|
|||||||
<template slot="append">{{ displayWithdrawSymbol }}</template>
|
<template slot="append">{{ displayWithdrawSymbol }}</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
<div class="balance-info">
|
<div class="balance-info">
|
||||||
<div class="balance-detail">
|
<div class="balance-total">钱包总余额:{{ totalBalance }} {{ displayWithdrawSymbol }}</div>
|
||||||
<span>可用余额:{{ (WalletData.walletBalance || WalletData.balance || 0) }} {{ displayWithdrawSymbol }}</span>
|
<div class="balance-row">
|
||||||
|
<span>可用余额:{{ availableWithdrawBalance }} {{ displayWithdrawSymbol }}</span>
|
||||||
|
<span class="divider">|</span>
|
||||||
|
<span class="frozen-info">
|
||||||
|
<el-tooltip placement="top" effect="dark">
|
||||||
|
<div slot="content">
|
||||||
|
冻结金额不能使用或提现,以下情况会冻结钱包余额:<br/>
|
||||||
|
1. 下单机器后会冻结订单对应金额<br/>
|
||||||
|
2. 提交提现后,金额正在提现中
|
||||||
</div>
|
</div>
|
||||||
<div class="balance-detail frozen-info">
|
<i class="el-icon-question frozen-tip-icon"></i>
|
||||||
<span>冻结余额:{{ (WalletData.blockedBalance || 0) }} {{ displayWithdrawSymbol }}</span>
|
</el-tooltip>
|
||||||
|
冻结余额:{{ (WalletData.blockedBalance || 0) }} {{ displayWithdrawSymbol }}
|
||||||
<span class="frozen-tip">(购买机器下单后冻结,不可提现)</span>
|
<span class="frozen-tip">(购买机器下单后冻结,不可提现)</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -255,6 +281,7 @@
|
|||||||
<el-dialog
|
<el-dialog
|
||||||
title="链上充值"
|
title="链上充值"
|
||||||
:visible.sync="createDialogVisible"
|
:visible.sync="createDialogVisible"
|
||||||
|
:close-on-click-modal="false" :close-on-press-escape="false"
|
||||||
width="520px"
|
width="520px"
|
||||||
>
|
>
|
||||||
<el-form label-width="120px">
|
<el-form label-width="120px">
|
||||||
@@ -405,22 +432,29 @@ export default {
|
|||||||
* 计算实际到账金额
|
* 计算实际到账金额
|
||||||
*/
|
*/
|
||||||
actualAmount() {
|
actualAmount() {
|
||||||
// 使用“分”为单位进行整数计算,避免浮点误差
|
// 使用 10^6 精度进行整数计算,避免浮点误差;展示时最多6位小数、去尾零
|
||||||
const amountCents = this.toCents(this.withdrawForm.amount)
|
const amountInt = this.toScaledInt(this.withdrawForm.amount)
|
||||||
const feeCents = this.toCents(this.withdrawForm.fee)
|
const feeInt = this.toScaledInt(this.withdrawForm.fee)
|
||||||
if (!Number.isFinite(amountCents) || !Number.isFinite(feeCents)) return '0.00'
|
if (!Number.isFinite(amountInt) || !Number.isFinite(feeInt)) return '0'
|
||||||
const resultCents = amountCents - feeCents
|
const result = amountInt - feeInt
|
||||||
return resultCents > 0 ? this.centsToAmountString(resultCents) : '0.00'
|
if (result <= 0) return '0'
|
||||||
|
return this.formatDec6FromInt(result)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算总余额(可用余额 + 冻结余额)
|
* 计算总余额(可用余额 + 冻结余额)
|
||||||
*/
|
*/
|
||||||
totalBalance() {
|
totalBalance() {
|
||||||
const available = parseFloat(this.walletBalance) || 0
|
const available = parseFloat(this.WalletData.walletBalance || this.WalletData.balance || this.walletBalance || 0) || 0
|
||||||
const blocked = parseFloat(this.blockedBalance) || 0
|
const blocked = parseFloat(this.WalletData.blockedBalance || this.blockedBalance || 0) || 0
|
||||||
return (available + blocked).toFixed(2)
|
return (available + blocked).toFixed(2)
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 可用余额(提现对话框时以当前卡片的钱包为准)
|
||||||
|
*/
|
||||||
|
availableWithdrawBalance() {
|
||||||
|
return (this.WalletData.walletBalance || this.WalletData.balance || 0)
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 提现展示单位(始终大写):优先当前 WalletData 的 fromSymbol/coin
|
* 提现展示单位(始终大写):优先当前 WalletData 的 fromSymbol/coin
|
||||||
*/
|
*/
|
||||||
@@ -511,11 +545,18 @@ export default {
|
|||||||
const type = Number(r && r.type)
|
const type = Number(r && r.type)
|
||||||
const signAmt = (type === 1) ? Math.abs(amt) : -Math.abs(amt) // 1 充值为正,0 支付/2 提现为负
|
const signAmt = (type === 1) ? Math.abs(amt) : -Math.abs(amt) // 1 充值为正,0 支付/2 提现为负
|
||||||
const typeLabel = type === 1 ? '充值' : (type === 2 ? '提现' : '支付')
|
const typeLabel = type === 1 ? '充值' : (type === 2 ? '提现' : '支付')
|
||||||
|
const status = Number(r && r.status)
|
||||||
|
const statusTextMap = { 0: '失败', 1: '成功', 2: '处理中', 3: '校验失败' }
|
||||||
|
const statusTagTypeMap = { 0: 'danger', 1: 'success', 2: 'warning', 3: 'danger' }
|
||||||
return {
|
return {
|
||||||
id: `${r && r.updateTime || ''}-${idx}`,
|
id: `${r && r.updateTime || ''}-${idx}`,
|
||||||
type: typeLabel,
|
type: typeLabel,
|
||||||
amount: Number(signAmt.toFixed(2)),
|
amount: signAmt,
|
||||||
time: this.formatApiTime(r && r.updateTime)
|
amountText: this.formatDec6(Math.abs(signAmt)),
|
||||||
|
time: this.formatApiTime(r && r.updateTime),
|
||||||
|
status,
|
||||||
|
statusText: statusTextMap[status] || '-',
|
||||||
|
statusTagType: statusTagTypeMap[status] || 'info'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.recentTransactions = mapped
|
this.recentTransactions = mapped
|
||||||
@@ -533,35 +574,69 @@ export default {
|
|||||||
if (!s) return ''
|
if (!s) return ''
|
||||||
return s.replace('T', ' ').replace('Z', '')
|
return s.replace('T', ' ').replace('Z', '')
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 金额显示:保留最多6位小数,直接截断不四舍五入;不补尾随0
|
||||||
|
*/
|
||||||
|
formatDec6(value) {
|
||||||
|
if (value === null || value === undefined || value === '') return '0'
|
||||||
|
let s = String(value)
|
||||||
|
if (/e/i.test(s)) {
|
||||||
|
const n = Number(value)
|
||||||
|
if (!Number.isFinite(n)) return '0'
|
||||||
|
s = n.toFixed(20).replace(/\.0+$/, '').replace(/(\.\d*?)0+$/, '$1')
|
||||||
|
}
|
||||||
|
const m = s.match(/^(-?)(\d+)(?:\.(\d+))?$/)
|
||||||
|
if (!m) return s
|
||||||
|
let intPart = m[2]
|
||||||
|
let decPart = m[3] || ''
|
||||||
|
if (decPart.length > 6) decPart = decPart.slice(0, 6)
|
||||||
|
return decPart ? `${intPart}.${decPart}` : intPart
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 将金额字符串转换为“分”为单位的整数
|
* 将金额字符串转换为“分”为单位的整数
|
||||||
*/
|
*/
|
||||||
toCents(amountStr) {
|
/**
|
||||||
|
* 将金额字符串转为按 10^6 精度的整数
|
||||||
|
*/
|
||||||
|
toScaledInt(amountStr, decimals = 6) {
|
||||||
if (amountStr === null || amountStr === undefined) return 0
|
if (amountStr === null || amountStr === undefined) return 0
|
||||||
const normalized = String(amountStr).trim()
|
const normalized = String(amountStr).trim()
|
||||||
if (normalized === '') return 0
|
if (normalized === '') return 0
|
||||||
// 使用正则确保是最多两位小数的数字格式
|
const re = new RegExp(`^\\d+(?:\\.(\\d{0,${decimals}}))?$`)
|
||||||
const match = normalized.match(/^\d+(?:\.(\d{0,2}))?$/)
|
const match = normalized.match(re)
|
||||||
if (!match) {
|
if (!match) {
|
||||||
const n = Number(normalized)
|
const n = Number(normalized)
|
||||||
if (!Number.isFinite(n)) return 0
|
if (!Number.isFinite(n)) return 0
|
||||||
return Math.round(n * 100)
|
const scale = Math.pow(10, decimals)
|
||||||
|
return Math.round(n * scale)
|
||||||
}
|
}
|
||||||
const [intPart, decPartRaw] = normalized.split('.')
|
const [intPart, decPartRaw] = normalized.split('.')
|
||||||
const decPart = (decPartRaw || '').padEnd(2, '0').slice(0, 2)
|
const decPart = (decPartRaw || '').padEnd(decimals, '0').slice(0, decimals)
|
||||||
return Number(intPart) * 100 + Number(decPart)
|
const scale = Math.pow(10, decimals)
|
||||||
|
return Number(intPart) * scale + Number(decPart)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将“分”为单位的整数转为字符串金额,固定两位小数
|
* 将“分”为单位的整数转为字符串金额,固定两位小数
|
||||||
*/
|
*/
|
||||||
centsToAmountString(cents) {
|
/**
|
||||||
const sign = cents < 0 ? '-' : ''
|
* 将按 10^6 精度的整数转为字符串金额,固定六位小数
|
||||||
const abs = Math.abs(cents)
|
*/
|
||||||
const intPart = Math.floor(abs / 100)
|
scaledIntToString(intVal, decimals = 6) {
|
||||||
const decPart = String(abs % 100).padStart(2, '0')
|
const sign = intVal < 0 ? '-' : ''
|
||||||
|
const abs = Math.abs(intVal)
|
||||||
|
const scale = Math.pow(10, decimals)
|
||||||
|
const intPart = Math.floor(abs / scale)
|
||||||
|
const decPart = String(abs % scale).padStart(decimals, '0')
|
||||||
return `${sign}${intPart}.${decPart}`
|
return `${sign}${intPart}.${decPart}`
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 将按10^6精度的整数转为最多6位小数字符串(不补零,不四舍五入)
|
||||||
|
*/
|
||||||
|
formatDec6FromInt(intVal) {
|
||||||
|
const s = this.scaledIntToString(intVal, 6)
|
||||||
|
return s.replace(/\.0+$/, '').replace(/(\.\d*?)0+$/, '$1')
|
||||||
|
},
|
||||||
async fetchWalletInfo(params) {
|
async fetchWalletInfo(params) {
|
||||||
try {
|
try {
|
||||||
const res = await getWalletInfo(params)
|
const res = await getWalletInfo(params)
|
||||||
@@ -786,6 +861,14 @@ export default {
|
|||||||
* 根据链更新手续费
|
* 根据链更新手续费
|
||||||
*/
|
*/
|
||||||
updateFeeByChain() {
|
updateFeeByChain() {
|
||||||
|
// 优先从当前钱包信息中读取提现手续费(后端字段:charge)
|
||||||
|
const walletCharge = (this.WalletData && (this.WalletData.charge != null ? this.WalletData.charge : this.WalletData.fee))
|
||||||
|
if (walletCharge != null && walletCharge !== '') {
|
||||||
|
const n = Number(walletCharge)
|
||||||
|
this.withdrawForm.fee = Number.isFinite(n) ? n.toFixed(2) : String(walletCharge)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 兜底:按链类型给一个默认手续费
|
||||||
const feeMap = {
|
const feeMap = {
|
||||||
tron: '1.00', // TRC20 手续费较低
|
tron: '1.00', // TRC20 手续费较低
|
||||||
ethereum: '5.00', // ERC20 手续费较高
|
ethereum: '5.00', // ERC20 手续费较高
|
||||||
@@ -811,6 +894,7 @@ export default {
|
|||||||
toSymbol: (this.WalletData && (this.WalletData.fromSymbol || this.WalletData.coin)) || this.withdrawForm.toSymbol,
|
toSymbol: (this.WalletData && (this.WalletData.fromSymbol || this.WalletData.coin)) || this.withdrawForm.toSymbol,
|
||||||
amount: parseFloat(this.withdrawForm.amount),
|
amount: parseFloat(this.withdrawForm.amount),
|
||||||
toAddress: this.withdrawForm.toAddress,
|
toAddress: this.withdrawForm.toAddress,
|
||||||
|
fromAddress: (this.WalletData && this.WalletData.fromAddress) || '',
|
||||||
code: this.withdrawForm.googleCode // 添加谷歌验证码
|
code: this.withdrawForm.googleCode // 添加谷歌验证码
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -872,31 +956,32 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 使用“分”为单位的整数校验
|
// 使用“分”为单位的整数校验
|
||||||
const amountCents = this.toCents(value)
|
const amountInt = this.toScaledInt(value)
|
||||||
if (!Number.isFinite(amountCents) || amountCents <= 0) {
|
if (!Number.isFinite(amountInt) || amountInt <= 0) {
|
||||||
callback(new Error('请输入有效的金额'))
|
callback(new Error('请输入有效的金额'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 手续费与总需求按相同精度计算
|
||||||
const feeCents = this.toCents(this.withdrawForm.fee)
|
const feeInt = this.toScaledInt(this.withdrawForm.fee)
|
||||||
const totalRequired = amountCents + feeCents
|
const totalRequired = amountInt + feeInt
|
||||||
|
|
||||||
// 钱包余额转分
|
// 钱包余额转分
|
||||||
const balanceCents = this.toCents(this.walletBalance)
|
const balanceInt = this.toScaledInt(this.walletBalance)
|
||||||
if (totalRequired > balanceCents) {
|
if (totalRequired > balanceInt) {
|
||||||
const totalText = this.centsToAmountString(totalRequired)
|
const totalText = this.scaledIntToString(totalRequired)
|
||||||
callback(new Error(`提现金额加上手续费(${totalText} USDT)不能超过钱包余额`))
|
callback(new Error(`提现金额加上手续费(${totalText} USDT)不能超过钱包余额`))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查最小提现金额
|
// 检查最小提现金额
|
||||||
if (amountCents < 1000) { // 10 USDT = 1000 分
|
// 最小提现金额 1 USDT
|
||||||
callback(new Error('最小提现金额为10 USDT'))
|
if (amountInt < 1000000) {
|
||||||
|
callback(new Error('最小提现金额为1 USDT'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查实际到账金额是否为正数
|
// 检查实际到账金额是否为正数(提现金额必须大于手续费)
|
||||||
if (amountCents <= feeCents) {
|
if (amountInt <= feeInt) {
|
||||||
callback(new Error('提现金额必须大于手续费'))
|
callback(new Error('提现金额必须大于手续费'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -924,10 +1009,10 @@ export default {
|
|||||||
if (firstDot !== -1) {
|
if (firstDot !== -1) {
|
||||||
v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '')
|
v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '')
|
||||||
}
|
}
|
||||||
// 最多两位小数
|
// 最多六位小数
|
||||||
if (firstDot !== -1) {
|
if (firstDot !== -1) {
|
||||||
const [intPart, decPart] = v.split('.')
|
const [intPart, decPart] = v.split('.')
|
||||||
v = intPart + '.' + (decPart ? decPart.slice(0, 2) : '')
|
v = intPart + '.' + (decPart ? decPart.slice(0, 6) : '')
|
||||||
}
|
}
|
||||||
// 限制整数部分长度,避免过大导致显示或后端处理异常,这里限制到 12 位(万亿级)
|
// 限制整数部分长度,避免过大导致显示或后端处理异常,这里限制到 12 位(万亿级)
|
||||||
const parts = v.split('.')
|
const parts = v.split('.')
|
||||||
@@ -1182,26 +1267,30 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.transaction-list {
|
.transaction-list {
|
||||||
max-height: 400px;
|
/* API 仅返回 <=5 条,使用自适应高度,避免滚动条 */
|
||||||
overflow-y: auto;
|
max-height: none;
|
||||||
|
overflow-y: visible;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.transaction-item {
|
.transaction-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 12px 0;
|
padding: 8px 0;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid #f0f0f0;
|
||||||
transition: background-color 0.2s ease;
|
transition: background-color 0.2s ease;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.transaction-item:hover {
|
.transaction-item:hover {
|
||||||
background-color: #f8f9fa;
|
background-color: #f8f9fa;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding-left: 8px;
|
padding-left: 6px;
|
||||||
padding-right: 8px;
|
padding-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.transaction-item:last-child {
|
.transaction-item:last-child {
|
||||||
@@ -1213,6 +1302,7 @@ export default {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
.transaction-status { align-self: flex-start; }
|
||||||
|
|
||||||
.transaction-type {
|
.transaction-type {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -1407,13 +1497,17 @@ export default {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.balance-detail {
|
.balance-total { margin-bottom: 4px; font-weight: 600; }
|
||||||
margin-bottom: 4px;
|
.balance-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
||||||
}
|
.divider { color: #ccc; }
|
||||||
|
|
||||||
.frozen-info {
|
.frozen-info {
|
||||||
color: #e6a23c;
|
color: #e6a23c;
|
||||||
}
|
}
|
||||||
|
.balance-tip-icon, .frozen-tip-icon {
|
||||||
|
margin-right: 4px;
|
||||||
|
color: #ffd666;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.frozen-tip {
|
.frozen-tip {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
|
|||||||
@@ -102,10 +102,13 @@
|
|||||||
<!-- <el-table-column label="机器总数" min-width="120">
|
<!-- <el-table-column label="机器总数" min-width="120">
|
||||||
<template #default="scope">{{ countMachines(scope.row) }}</template>
|
<template #default="scope">{{ countMachines(scope.row) }}</template>
|
||||||
</el-table-column> -->
|
</el-table-column> -->
|
||||||
<el-table-column label="总价(USDT)" >
|
<el-table-column prop="totalPrice" label="总价(USDT)">
|
||||||
<template #default="scope"><span class="price-strong">{{ formatTrunc(computeShopTotal(scope.row), 2) }}</span></template>
|
<template #default="scope">
|
||||||
|
<span class="price-strong">{{ computeShopTotalDisplay(scope.row) }}</span>
|
||||||
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|
||||||
<el-table-column label="支付方式">
|
<el-table-column label="支付方式">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<img v-for="(item,index ) in scope.row.payConfigList" :key="index" :src="item.payCoinImage" :alt="item.payChain" :title="formatPayTooltip(item)" style="width: 20px; height: 20px; margin-right: 10px;" />
|
<img v-for="(item,index ) in scope.row.payConfigList" :key="index" :src="item.payCoinImage" :alt="item.payChain" :title="formatPayTooltip(item)" style="width: 20px; height: 20px; margin-right: 10px;" />
|
||||||
@@ -128,20 +131,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-dialog :visible.sync="confirmDialog.visible" width="720px" :close-on-click-modal="false" :title="`确认结算该店铺订单(共 ${confirmDialog.count} 台机器)`">
|
<el-dialog :visible.sync="confirmDialog.visible" width="80vw" :close-on-click-modal="false" :title="`确认结算该店铺订单(共 ${confirmDialog.count} 台机器)`">
|
||||||
<div>
|
<div>
|
||||||
<el-table :data="confirmDialog.items" height="360" border stripe
|
<el-table :data="confirmDialog.items" height="360" border stripe
|
||||||
:header-cell-style="{ textAlign: 'left' }" :cell-style="{ textAlign: 'left' }">
|
:header-cell-style="{ textAlign: 'left' }" :cell-style="{ textAlign: 'left' }">
|
||||||
<el-table-column prop="product" label="商品" min-width="160" />
|
<el-table-column prop="product" label="商品" min-width="160" />
|
||||||
<el-table-column prop="coin" label="币种" min-width="100" />
|
<el-table-column prop="coin" label="币种" min-width="100" />
|
||||||
<el-table-column prop="machineId" label="机器ID" min-width="100" />
|
|
||||||
<el-table-column prop="user" label="账户" min-width="120" />
|
<el-table-column prop="user" label="账户" min-width="120" />
|
||||||
<el-table-column prop="miner" label="机器编号" min-width="160" />
|
<el-table-column prop="miner" label="机器编号" min-width="160" />
|
||||||
<el-table-column prop="price" min-width="120">
|
<el-table-column prop="unitPrice" min-width="140">
|
||||||
<template #header>单价({{ payCoinSymbol || 'USDT' }})</template>
|
<template #header>单价({{ payCoinSymbol || 'USDT' }})</template>
|
||||||
|
<template #default="scope"><span class="price-strong">{{ formatTrunc(scope.row.unitPrice, 2) }}</span></template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="leaseTime" label="租赁天数" min-width="120" />
|
||||||
|
<el-table-column prop="subtotal" min-width="140">
|
||||||
|
<template #header>小计({{ payCoinSymbol || 'USDT' }})</template>
|
||||||
|
<template #default="scope"><span class="price-strong">{{ formatTrunc(scope.row.subtotal, 2) }}</span></template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div style="margin-top:12px;text-align:right;">总金额({{ payCoinSymbol || 'USDT' }}):<b>{{ formatTrunc(confirmDialog.total, 2) }}</b></div>
|
<div style="margin-top:12px;text-align:right;">总金额({{ payCoinSymbol || 'USDT' }}):<span class="price-strong">{{ formatTrunc(confirmDialog.total, 2) }}</span></div>
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="confirmDialog.visible=false">取消</el-button>
|
<el-button @click="confirmDialog.visible=false">取消</el-button>
|
||||||
@@ -166,20 +174,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 结算成功提示弹窗 -->
|
|
||||||
<el-dialog :visible.sync="successDialog.visible" width="480px" :close-on-click-modal="false" :close-on-press-escape="false" @close="handleCloseSuccessDialog">
|
|
||||||
<div style="text-align:center; padding: 20px 0;">
|
|
||||||
<div style="font-size: 48px; color: #52c41a; margin-bottom: 16px;">✓</div>
|
|
||||||
<div style="font-size: 18px; color: #333; margin-bottom: 12px;">请求结算处理成功</div>
|
|
||||||
<div style="color: #666; line-height: 1.6;">
|
|
||||||
请在订单列表页面查看结算状态<br>
|
|
||||||
结算成功会自动更新钱包余额
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<template #footer>
|
|
||||||
<el-button type="primary" @click="handleCloseSuccessDialog">已知晓</el-button>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<!-- 购物须知(测试版) - 必须勾选并等待5秒后才可关闭 -->
|
<!-- 购物须知(测试版) - 必须勾选并等待5秒后才可关闭 -->
|
||||||
<el-dialog :visible.sync="noticeDialog.visible" width="680px" title="下单须知" :show-close="false" :close-on-click-modal="false" :close-on-press-escape="false">
|
<el-dialog :visible.sync="noticeDialog.visible" width="680px" title="下单须知" :show-close="false" :close-on-click-modal="false" :close-on-press-escape="false">
|
||||||
@@ -252,7 +247,22 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 结算成功提示弹窗(全局,避免被父级条件渲染影响) -->
|
||||||
|
<el-dialog :visible.sync="settlementSuccessfulVisible" width="480px" append-to-body :close-on-click-modal="false" :close-on-press-escape="false" @close="handleCloseSuccessDialog">
|
||||||
|
<div style="text-align:center; padding: 20px 0;">
|
||||||
|
<div style="font-size: 48px; color: #52c41a; margin-bottom: 16px;">✓</div>
|
||||||
|
<div style="font-size: 18px; color: #333; margin-bottom: 12px;">请求结算处理成功</div>
|
||||||
|
<div style="color: #666; line-height: 1.6;">
|
||||||
|
请在订单列表页面查看结算状态<br>
|
||||||
|
结算成功会自动更新钱包余额
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<el-button type="primary" @click="handleCloseSuccessDialog">已知晓</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -292,7 +302,8 @@ export default {
|
|||||||
selectedChain: '',
|
selectedChain: '',
|
||||||
selectedCoin: '',
|
selectedCoin: '',
|
||||||
selectedPrice: 0
|
selectedPrice: 0
|
||||||
,clearOffLoading: false
|
,clearOffLoading: false,
|
||||||
|
settlementSuccessfulVisible: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -368,10 +379,45 @@ export default {
|
|||||||
this.noticeTimer = null
|
this.noticeTimer = null
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* 将金额转为整分整数,避免浮点误差
|
||||||
|
* @param {number|string} v
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
toCents(v) {
|
||||||
|
// 直接截取两位小数(不四舍五入),并转为“分”的整数
|
||||||
|
if (v === null || v === undefined) return 0
|
||||||
|
let s = String(v).trim()
|
||||||
|
if (s === '') return 0
|
||||||
|
let sign = 1
|
||||||
|
if (s[0] === '-') { sign = -1; s = s.slice(1) }
|
||||||
|
const parts = s.split('.')
|
||||||
|
const intPart = parseInt(parts[0] || '0', 10) || 0
|
||||||
|
const decRaw = (parts[1] || '').replace(/[^0-9]/g, '')
|
||||||
|
const decTwo = (decRaw.length >= 2 ? decRaw.slice(0, 2) : decRaw.padEnd(2, '0'))
|
||||||
|
const cents = intPart * 100 + (parseInt(decTwo || '0', 10) || 0)
|
||||||
|
return sign * cents
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 整分转字符串,固定两位小数
|
||||||
|
* @param {number} cents
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
centsToText(cents) {
|
||||||
|
const sign = cents < 0 ? '-' : ''
|
||||||
|
const abs = Math.abs(Number(cents) || 0)
|
||||||
|
const intPart = Math.floor(abs / 100)
|
||||||
|
const decPart = String(abs % 100).padStart(2, '0')
|
||||||
|
return `${sign}${intPart}.${decPart}`
|
||||||
|
},
|
||||||
// 选择框可选逻辑:下架(或删除)机器不可选择
|
// 选择框可选逻辑:下架(或删除)机器不可选择
|
||||||
isRowSelectable(row, index) {
|
isRowSelectable(row, index) {
|
||||||
return !(Number(row && row.del) === 1 || Number(row && row.state) === 1)
|
return !(Number(row && row.del) === 1 || Number(row && row.state) === 1)
|
||||||
},
|
},
|
||||||
|
// 判断机器是否“上架”(用于未展开时的自动筛选)
|
||||||
|
isOnShelf(row) {
|
||||||
|
return !(Number(row && row.del) === 1 || Number(row && row.state) === 1)
|
||||||
|
},
|
||||||
// 获取本地最大可租赁天数,默认 365
|
// 获取本地最大可租赁天数,默认 365
|
||||||
getRowMaxLeaseDaysLocal(row) {
|
getRowMaxLeaseDaysLocal(row) {
|
||||||
const raw = row && row.maxLeaseDays
|
const raw = row && row.maxLeaseDays
|
||||||
@@ -402,6 +448,11 @@ export default {
|
|||||||
},
|
},
|
||||||
//获取支持的链和币种
|
//获取支持的链和币种
|
||||||
async fetchChainAndListForSeller(shopId) {
|
async fetchChainAndListForSeller(shopId) {
|
||||||
|
if (!shopId) {
|
||||||
|
this.options = []
|
||||||
|
this.loading = false
|
||||||
|
return
|
||||||
|
}
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const res = await getChainAndListForSeller({ id: shopId });
|
const res = await getChainAndListForSeller({ id: shopId });
|
||||||
if (res && (res.code === 0 || res.code === 200) && res.data) {
|
if (res && (res.code === 0 || res.code === 200) && res.data) {
|
||||||
@@ -425,10 +476,42 @@ export default {
|
|||||||
},
|
},
|
||||||
// 获取所有商品分组(兼容保留,现直接返回空,因已移除中间商品层)
|
// 获取所有商品分组(兼容保留,现直接返回空,因已移除中间商品层)
|
||||||
getAllGroups() { return [] },
|
getAllGroups() { return [] },
|
||||||
// 店铺总价 = 累加其所有商品的 (机器单价 × 租赁天数)
|
// 店铺总价(精确到分):优先用后端 totalPrice;若用户改动租期则实时按分计算
|
||||||
computeShopTotal(shop) {
|
computeShopTotal(shop) {
|
||||||
|
if (!shop) return 0
|
||||||
|
const list = Array.isArray(shop.productMachineDtoList) ? shop.productMachineDtoList : []
|
||||||
|
// 若没有子项,直接返回后端值
|
||||||
|
if (!list.length) return Number(shop.totalPrice || 0)
|
||||||
|
let totalCents = 0
|
||||||
|
for (const m of list) {
|
||||||
|
const priceCents = this.toCents(m && m.price)
|
||||||
|
const days = Math.max(1, Math.floor(Number(m && m.leaseTime) || 1))
|
||||||
|
totalCents += priceCents * days
|
||||||
|
}
|
||||||
|
return totalCents / 100
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 返回展示用字符串:两位小数且无精度丢失
|
||||||
|
*/
|
||||||
|
computeShopTotalDisplay(shop) {
|
||||||
const list = Array.isArray(shop && shop.productMachineDtoList) ? shop.productMachineDtoList : []
|
const list = Array.isArray(shop && shop.productMachineDtoList) ? shop.productMachineDtoList : []
|
||||||
return list.reduce((sum, m) => sum + Number(m.price || 0) * Number(m.leaseTime || 1), 0)
|
const backendVal = Number(shop && shop.totalPrice)
|
||||||
|
const hasBackend = Number.isFinite(backendVal)
|
||||||
|
// 若未修改任一机器租期,优先展示后端总价
|
||||||
|
let modified = false
|
||||||
|
for (const m of list) {
|
||||||
|
const orig = (m && m._origLeaseTime != null) ? Number(m._origLeaseTime) : Number(m && m.leaseTime)
|
||||||
|
const cur = Math.max(1, Math.floor(Number(m && m.leaseTime) || 1))
|
||||||
|
if (orig !== cur) { modified = true; break }
|
||||||
|
}
|
||||||
|
if ((hasBackend && !modified) || (!list.length && hasBackend)) return this.formatTrunc(backendVal, 2)
|
||||||
|
let totalCents = 0
|
||||||
|
for (const m of list) {
|
||||||
|
const priceCents = this.toCents(m && m.price)
|
||||||
|
const days = Math.max(1, Math.floor(Number(m && m.leaseTime) || 1))
|
||||||
|
totalCents += priceCents * days
|
||||||
|
}
|
||||||
|
return this.centsToText(totalCents)
|
||||||
},
|
},
|
||||||
// 组装批量删除的请求体:数组 [{ machineId, productId }]
|
// 组装批量删除的请求体:数组 [{ machineId, productId }]
|
||||||
buildDeletePayload() {
|
buildDeletePayload() {
|
||||||
@@ -548,6 +631,13 @@ export default {
|
|||||||
...shop,
|
...shop,
|
||||||
id: shop.id != null ? String(shop.id) : `shop-${sIdx}`
|
id: shop.id != null ? String(shop.id) : `shop-${sIdx}`
|
||||||
}))
|
}))
|
||||||
|
// 记录每台机器的原始租期,便于判断是否被修改
|
||||||
|
try {
|
||||||
|
withShopKeys.forEach(sp => {
|
||||||
|
const list = Array.isArray(sp.productMachineDtoList) ? sp.productMachineDtoList : []
|
||||||
|
list.forEach(m => { if (m && m._origLeaseTime == null) m._origLeaseTime = Number(m.leaseTime || 1) })
|
||||||
|
})
|
||||||
|
} catch (e) { /* noop */ }
|
||||||
this.shops = withShopKeys
|
this.shops = withShopKeys
|
||||||
this.groups = []
|
this.groups = []
|
||||||
this.expandedGroupKeys = []
|
this.expandedGroupKeys = []
|
||||||
@@ -681,7 +771,7 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
machines.forEach(m => {
|
machines.forEach(m => {
|
||||||
if (selectedSet.has(m.id)) {
|
if (selectedSet.has(m.id) && this.isOnShelf(m)) {
|
||||||
payload.push({
|
payload.push({
|
||||||
leaseTime: Number(m.leaseTime || 1),
|
leaseTime: Number(m.leaseTime || 1),
|
||||||
machineId: m.id,
|
machineId: m.id,
|
||||||
@@ -690,9 +780,18 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (!payload.length) {
|
||||||
|
this.$message({ message: '所选机器均已下架,无法结算', type: 'warning', showClose: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 未展开:默认使用全部机器
|
// 未展开:仅结算“上架”机器
|
||||||
machines.forEach(m => {
|
const onShelfMachines = machines.filter(m => this.isOnShelf(m))
|
||||||
|
if (!onShelfMachines.length) {
|
||||||
|
this.$message({ message: '该店铺暂无上架机器可结算', type: 'warning', showClose: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
onShelfMachines.forEach(m => {
|
||||||
payload.push({
|
payload.push({
|
||||||
leaseTime: Number(m.leaseTime || 1),
|
leaseTime: Number(m.leaseTime || 1),
|
||||||
machineId: m.id,
|
machineId: m.id,
|
||||||
@@ -723,11 +822,18 @@ export default {
|
|||||||
if (res && Number(res.code) === 200) {
|
if (res && Number(res.code) === 200) {
|
||||||
const dataStr = String(res.data || '')
|
const dataStr = String(res.data || '')
|
||||||
ok = dataStr.includes('成功')
|
ok = dataStr.includes('成功')
|
||||||
|
this.$message({
|
||||||
|
message: `结算成功,订单状态请在订单列表中查看`,
|
||||||
|
type: 'success',
|
||||||
|
duration: 3000,
|
||||||
|
showClose: true,
|
||||||
|
})
|
||||||
|
this.settlementSuccessfulVisible = true
|
||||||
}
|
}
|
||||||
if (ok) {
|
if (ok) {
|
||||||
// 结算成功后重新获取购物车数据,更新购物车数量
|
// 结算成功后重新获取购物车数据,更新购物车数量
|
||||||
await this.fetchGetGoodsList()
|
await this.fetchGetGoodsList()
|
||||||
this.successDialog.visible = true
|
// this.settlementSuccessfulVisible = true
|
||||||
} else {
|
} else {
|
||||||
// 失败或未成功,恢复之前的勾选 UI
|
// 失败或未成功,恢复之前的勾选 UI
|
||||||
this.reapplySelectionsForPendingShop()
|
this.reapplySelectionsForPendingShop()
|
||||||
@@ -823,7 +929,7 @@ export default {
|
|||||||
},
|
},
|
||||||
// 关闭成功弹窗:跳转到订单列表的订单进行中状态
|
// 关闭成功弹窗:跳转到订单列表的订单进行中状态
|
||||||
handleCloseSuccessDialog() {
|
handleCloseSuccessDialog() {
|
||||||
try { this.successDialog.visible = false } catch (e) { /* noop */ }
|
try { this.settlementSuccessfulVisible = false } catch (e) { /* noop */ }
|
||||||
this.$router.push({ path: '/account/orders', query: { status: '7' } })
|
this.$router.push({ path: '/account/orders', query: { status: '7' } })
|
||||||
},
|
},
|
||||||
// 注意事项:启动 5 秒倒计时
|
// 注意事项:启动 5 秒倒计时
|
||||||
@@ -910,24 +1016,28 @@ export default {
|
|||||||
|
|
||||||
const items = []
|
const items = []
|
||||||
list.forEach(m => {
|
list.forEach(m => {
|
||||||
if (selectedIds.has(m.id)) {
|
if (selectedIds.has(m.id) && this.isOnShelf(m)) {
|
||||||
const usdtPrice = Number(m.price || 0) * Number(m.leaseTime || 1)
|
// 单价(同币种显示,若非USDT按实时价换算)
|
||||||
|
const baseUnit = Number(m.price || 0)
|
||||||
|
const leaseDays = Math.max(1, Math.floor(Number(m.leaseTime || 1)))
|
||||||
const isUSDT = String(this.selectedCoin).toUpperCase() === 'USDT'
|
const isUSDT = String(this.selectedCoin).toUpperCase() === 'USDT'
|
||||||
const displayPrice = !isUSDT && this.selectedPrice > 0 ? (usdtPrice / this.selectedPrice) : usdtPrice
|
const unitPrice = !isUSDT && this.selectedPrice > 0 ? (baseUnit / this.selectedPrice) : baseUnit
|
||||||
|
const subtotal = unitPrice * leaseDays
|
||||||
items.push({
|
items.push({
|
||||||
product: shop.name || '',
|
product: shop.name || '',
|
||||||
coin: this.toUpperText(m.coin),
|
coin: this.toUpperText(m.coin),
|
||||||
machineId: m.id,
|
|
||||||
user: m.user,
|
user: m.user,
|
||||||
miner: m.miner,
|
miner: m.miner,
|
||||||
price: Number(displayPrice || 0)
|
unitPrice: Number(unitPrice || 0),
|
||||||
|
leaseTime: leaseDays,
|
||||||
|
subtotal: Number(subtotal || 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.confirmDialog.items = items
|
this.confirmDialog.items = items
|
||||||
this.confirmDialog.count = items.length
|
this.confirmDialog.count = items.length
|
||||||
this.confirmDialog.total = items.reduce((s, i) => s + i.price, 0)
|
this.confirmDialog.total = items.reduce((s, i) => s + i.subtotal, 0)
|
||||||
this.confirmDialog.visible = true
|
this.confirmDialog.visible = true
|
||||||
},
|
},
|
||||||
// 显示谷歌验证码输入框
|
// 显示谷歌验证码输入框
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
|
|
||||||
<!-- 外层列宽同样收紧,避免横向滚动 -->
|
<!-- 外层列宽同样收紧,避免横向滚动 -->
|
||||||
<el-table-column label="价格 (USDT)" header-align="left" align="left" min-width="120">
|
<el-table-column label="价格 (USDT)" header-align="left" align="left" min-width="120">
|
||||||
<template slot-scope="scope">{{ scope.row.productMachineRangeGroupDto && scope.row.productMachineRangeGroupDto.price }} </template>
|
<template slot-scope="scope"><span class="price-strong">{{ scope.row.productMachineRangeGroupDto && scope.row.productMachineRangeGroupDto.price }}</span></template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column label="理论算力范围" min-width="220" header-align="left" align="left" show-overflow-tooltip>
|
<el-table-column label="理论算力范围" min-width="220" header-align="left" align="left" show-overflow-tooltip>
|
||||||
@@ -132,20 +132,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 确认加入购物车弹窗 -->
|
<!-- 确认加入购物车弹窗 -->
|
||||||
<el-dialog :visible.sync="confirmAddDialog.visible" width="60vw" :title="`确认加入购物车(共 ${confirmAddDialog.items.length} 台)`">
|
<el-dialog :visible.sync="confirmAddDialog.visible" width="80vw" :title="`确认加入购物车(共 ${confirmAddDialog.items.length} 台)`">
|
||||||
<div>
|
<div>
|
||||||
<el-table :data="confirmAddDialog.items" height="360" border stripe :header-cell-style="{ textAlign: 'left' }" :cell-style="{ textAlign: 'left' }">
|
<el-table :data="confirmAddDialog.items" height="360" border stripe :header-cell-style="{ textAlign: 'left' }" :cell-style="{ textAlign: 'left' }">
|
||||||
<el-table-column prop="type" label="型号" width="160" header-align="left" align="left" />
|
<el-table-column prop="theoryPower" label="理论算力" header-align="left" align="left" />
|
||||||
<el-table-column prop="theoryPower" label="理论算力" width="160" header-align="left" align="left" />
|
<el-table-column label="实际算力" header-align="left" align="left">
|
||||||
<el-table-column label="算力" width="160" header-align="left" align="left">
|
|
||||||
<template #default="scope">{{ scope.row.computingPower }} {{ scope.row.unit }}</template>
|
<template #default="scope">{{ scope.row.computingPower }} {{ scope.row.unit }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="algorithm" label="算法" width="120" header-align="left" align="left" />
|
<el-table-column prop="algorithm" label="算法" width="120" header-align="left" align="left" />
|
||||||
<el-table-column prop="powerDissipation" label="功耗(kw/h)" width="160" header-align="left" align="left" />
|
<el-table-column prop="powerDissipation" label="功耗(kw/h)" header-align="left" align="left" />
|
||||||
<el-table-column label="租赁天数(天)" width="160" header-align="left" align="left">
|
<el-table-column label="租赁天数(天)" header-align="left" align="left">
|
||||||
<template #default="scope">{{ Number(scope.row.leaseTime || 1) }}</template>
|
<template #default="scope">{{ Number(scope.row.leaseTime || 1) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="price" label="单价(USDT)" width="160" header-align="left" align="left" />
|
<el-table-column prop="price" label="单价(USDT)" header-align="left" align="left">
|
||||||
|
<template #default="scope"><span class="price-strong">{{ scope.row.price }}</span></template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
@@ -350,6 +351,11 @@ export default {
|
|||||||
color: #e74c3c;
|
color: #e74c3c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.price-strong {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #e74c3c;
|
||||||
|
}
|
||||||
|
|
||||||
/* 支付方式区域(视觉更友好 + 可达性) */
|
/* 支付方式区域(视觉更友好 + 可达性) */
|
||||||
.pay-methods {
|
.pay-methods {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -35,44 +35,44 @@ export default {
|
|||||||
],
|
],
|
||||||
loading: false,
|
loading: false,
|
||||||
powerList: [
|
powerList: [
|
||||||
{
|
// {
|
||||||
value: 1,
|
// value: 1,
|
||||||
label: "NexaPow",
|
// label: "NexaPow",
|
||||||
children: [
|
// children: [
|
||||||
{
|
// {
|
||||||
value: 1 - 1,
|
// value: 1 - 1,
|
||||||
label: "挖矿账户1",
|
// label: "挖矿账户1",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
value: 1 - 2,
|
// value: 1 - 2,
|
||||||
label: "挖矿账户2",
|
// label: "挖矿账户2",
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
value: 2,
|
// value: 2,
|
||||||
label: "Grepow",
|
// label: "Grepow",
|
||||||
children: [
|
// children: [
|
||||||
{
|
// {
|
||||||
value: 2 - 1,
|
// value: 2 - 1,
|
||||||
label: "挖矿账户1",
|
// label: "挖矿账户1",
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
value: 2 - 2,
|
// value: 2 - 2,
|
||||||
label: "挖矿账户2",
|
// label: "挖矿账户2",
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
value: 3,
|
// value: 3,
|
||||||
label: "mofang",
|
// label: "mofang",
|
||||||
children: [
|
// children: [
|
||||||
{
|
// {
|
||||||
value: 3 - 1,
|
// value: 3 - 1,
|
||||||
label: "挖矿账户1",
|
// label: "挖矿账户1",
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
],
|
],
|
||||||
currencyList: [
|
currencyList: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -54,7 +54,8 @@
|
|||||||
tabindex="0"
|
tabindex="0"
|
||||||
aria-label="查看详情"
|
aria-label="查看详情"
|
||||||
>
|
>
|
||||||
<img :src="product.image || 'https://img.yzcdn.cn/vant/apple-1.jpg'" :alt="product.name" class="product-image" />
|
<!-- <img :src="product.image || 'https://img.yzcdn.cn/vant/apple-1.jpg'" :alt="product.name" class="product-image" /> -->
|
||||||
|
<img src="../../assets/imgs/commodity.png" :alt="product.name" class="product-image" />
|
||||||
<div class="product-info">
|
<div class="product-info">
|
||||||
<h4>商品: {{ product.name }}</h4>
|
<h4>商品: {{ product.name }}</h4>
|
||||||
<p style="font-size: 16px;margin-top: 10px;font-weight: bold;">算法: {{ product.algorithm }}</p>
|
<p style="font-size: 16px;margin-top: 10px;font-weight: bold;">算法: {{ product.algorithm }}</p>
|
||||||
@@ -166,10 +167,10 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 35vh;
|
height: 40vh;
|
||||||
}
|
}
|
||||||
.product-image {
|
.product-image {
|
||||||
width: 90%;
|
width: 68%;
|
||||||
height:65%;
|
height:65%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
|||||||
Binary file not shown.
1
power_leasing/test/css/app.9d232bce.css
Normal file
1
power_leasing/test/css/app.9d232bce.css
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>power_leasing</title><script defer="defer" src="/js/chunk-vendors.f4da7ffe.js"></script><script defer="defer" src="/js/app.e19a35c5.js"></script><link href="/css/chunk-vendors.10dd4e95.css" rel="stylesheet"><link href="/css/app.95fce3d4.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but power_leasing doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>power_leasing</title><script defer="defer" src="/js/chunk-vendors.f4da7ffe.js"></script><script defer="defer" src="/js/app.7b715e42.js"></script><link href="/css/chunk-vendors.10dd4e95.css" rel="stylesheet"><link href="/css/app.9d232bce.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but power_leasing doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||||
2
power_leasing/test/js/app.7b715e42.js
Normal file
2
power_leasing/test/js/app.7b715e42.js
Normal file
File diff suppressed because one or more lines are too long
1
power_leasing/test/js/app.7b715e42.js.map
Normal file
1
power_leasing/test/js/app.7b715e42.js.map
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user