每周更新

This commit is contained in:
2026-01-16 15:03:50 +08:00
parent cb0a715f4a
commit da223f8935
28 changed files with 738 additions and 888 deletions

View File

@@ -222,6 +222,15 @@
@input="handleEditFeeRateInput"
/>
</div>
<div class="row">
<label class="label">谷歌验证码</label>
<el-input
v-model="editForm.gCode"
placeholder="请输入6位谷歌验证码"
maxlength="6"
@input="handleEditShopGoogleCodeInput"
/>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="visibleEdit=false">取消</el-button>
@@ -263,7 +272,7 @@ import { getMyShop, updateShop, deleteShop, queryShop, closeShop ,updateShopConf
import { coinList } from '@/utils/coinList'
import { getShopConfig,getShopConfigV2 ,withdrawBalanceForSeller,updateShopConfigV2} from '@/api/wallet'
import { rsaEncrypt, rsaEncryptSync } from '@/utils/rsaEncrypt'
import { getGoogleStatus } from '@/api/verification'
export default {
name: 'AccountMyShops',
@@ -281,7 +290,7 @@ export default {
state: 0
},
visibleEdit: false,
editForm: { id: '', name: '', image: '', description: '', feeRate: '' },
editForm: { id: '', name: '', image: '', description: '', feeRate: '', gCode: '' },
// 店铺配置列表
shopConfigs: [],
visibleConfigEdit: false,
@@ -370,6 +379,58 @@ export default {
this.fetchMyShop()
},
methods: {
/**
* 修改店铺谷歌验证码输入仅数字最多6位
*/
handleEditShopGoogleCodeInput(v) {
this.editForm.gCode = String(v || '').replace(/\D/g, '').slice(0, 6)
},
/**
* 钱包相关敏感操作前置校验必须已开启双重验证Google Authenticator
* getGoogleStatus 返回值0 开启1 未绑定2 关闭
*
* - status=0允许继续操作
* - status=1/2弹窗提示并阻止操作可跳转到“安全设置”页面开启/绑定
*
* @param {string} actionLabel - 操作名称(用于文案:如“提现/修改/删除”)
* @returns {Promise<boolean>} 是否允许继续
*/
async ensureGoogleStatusEnabledForWalletOp(actionLabel) {
try {
const res = await getGoogleStatus()
if (!res || !(res.code === 0 || res.code === 200)) {
this.$message.error('获取双重验证状态失败,请稍后重试')
return false
}
const status = (res && res.data && res.data.status != null) ? res.data.status : (res.data ?? 1)
if (Number(status) === 0) return true
const title = '安全提示'
const reason = Number(status) === 1 ? '您尚未绑定双重验证' : '您已关闭双重验证'
const message = `
<div class="google-2fa-guard__content">
<div class="google-2fa-guard__title">${reason}</div>
<div class="google-2fa-guard__desc">
请先在<strong>安全设置</strong>中绑定并开启双重验证后,才可以进行<strong>${actionLabel || '该'}操作</strong>。
</div>
</div>
`
await this.$confirm(message, title, {
confirmButtonText: '去安全设置',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true,
customClass: 'google-2fa-guard-dialog'
})
this.$router.push('/account/security-settings')
return false
} catch (e) {
// 用户取消弹窗或接口异常都视为不允许继续
return false
}
},
/** 余额展示:带币种单位 */
formatBalance(row) {
try {
@@ -399,6 +460,9 @@ export default {
},
/** 打开提现对话框(行数据驱动) */
async handleWithdraw(row) {
const ok = await this.ensureGoogleStatusEnabledForWalletOp('提现')
if (!ok) return
this.currentWithdrawRow = row || {}
const fee = Number(row && (row.serviceCharge != null ? row.serviceCharge : row.charge))
this.withdrawForm.fee = Number.isFinite(fee) ? this.formatDec6(fee) : '0.00'
@@ -413,7 +477,10 @@ export default {
{ required: true, message: '请输入提现金额', trigger: 'blur' },
{ validator: this.validateWithdrawAmount, trigger: 'blur' }
],
// 地址为只读已填,不再要求用户输入
toAddress: [
{ required: true, message: '请输入收款钱包地址', trigger: 'blur' },
{ validator: this.validateWithdrawToAddress, trigger: 'blur' }
],
googleCode: [
{ required: true, message: '请输入谷歌验证码', trigger: 'blur' },
{ validator: this.validateGoogleCode, trigger: 'blur' }
@@ -584,6 +651,17 @@ export default {
if (!/^\d{6}$/.test(v)) { callback(new Error('谷歌验证码必须是6位数字')); return }
callback()
},
/**
* 校验:收款地址不能为空
* @param {any} rule
* @param {string} value
* @param {(err?: Error) => void} callback
*/
validateWithdrawToAddress(rule, value, callback) {
const v = String(value || '').trim()
if (!v) { callback(new Error('请输入收款钱包地址')); return }
callback()
},
/**
* 手续费率显示最多6位小数去除多余的0空值显示为 '-'
*/
@@ -707,6 +785,9 @@ export default {
}
},
async handleEditConfig(row) {
const ok = await this.ensureGoogleStatusEnabledForWalletOp('修改')
if (!ok) return
try {
const res = await getChainAndCoin({ id: row.id })
if (res && (res.code === 0 || res.code === 200) && res.data) {
@@ -745,7 +826,31 @@ export default {
}
},
async handleDeleteConfig(row) {
this.deleteShopConfig({id:row.id})
const ok = await this.ensureGoogleStatusEnabledForWalletOp('删除')
if (!ok) return
try {
const { value } = await this.$prompt(
'请输入 6 位谷歌验证码以删除该钱包绑定配置',
'安全验证',
{
confirmButtonText: '确认删除',
cancelButtonText: '取消',
type: 'warning',
inputPlaceholder: '6位数字验证码',
inputPattern: /^\d{6}$/,
inputErrorMessage: '谷歌验证码必须是6位数字'
}
)
const gCode = String(value || '').trim()
if (!/^\d{6}$/.test(gCode)) {
this.$message.warning('谷歌验证码必须是6位数字')
return
}
await this.deleteShopConfig({ id: row.id, gCode })
} catch (e) {
// 用户取消或弹窗关闭
}
},
/**
@@ -828,6 +933,8 @@ export default {
this.configForm.payCoins = (this.configForm.payCoins || []).filter(v => String(v) !== String(value))
},
async handleOpenEdit() {
const ok = await this.ensureGoogleStatusEnabledForWalletOp('修改店铺')
if (!ok) return
try {
// 先打开弹窗,提供更快的视觉反馈
this.visibleEdit = true
@@ -839,7 +946,8 @@ export default {
name: res.data.name,
image: res.data.image,
description: res.data.description,
feeRate: res.data.feeRate
feeRate: res.data.feeRate,
gCode: ''
}
@@ -850,7 +958,8 @@ export default {
name: this.shop.name,
image: this.shop.image,
description: this.shop.description,
feeRate: this.shop.feeRate
feeRate: this.shop.feeRate,
gCode: ''
}
this.$message.warning(res && res.msg ? res.msg : '未获取到店铺详情')
}
@@ -861,7 +970,8 @@ export default {
name: this.shop.name,
image: this.shop.image,
description: this.shop.description,
feeRate: this.shop.feeRate
feeRate: this.shop.feeRate,
gCode: ''
}
console.error('查询店铺详情失败:', error)
@@ -918,7 +1028,14 @@ export default {
}
this.editForm.feeRate = rateNum.toString()
const payload = { ...this.editForm }
// 谷歌验证码:必填 6 位数字
const gCode = String(this.editForm.gCode || '').trim()
if (!/^\d{6}$/.test(gCode)) {
this.$message.warning('请输入6位谷歌验证码')
return
}
const payload = { ...this.editForm, gCode }
const res = await updateShop(payload)
if (res && (res.code === 0 || res.code === 200)) {
this.$message({
@@ -941,9 +1058,27 @@ export default {
}
},
async handleDelete() {
const ok = await this.ensureGoogleStatusEnabledForWalletOp('删除店铺')
if (!ok) return
try {
await this.$confirm('确定删除该店铺吗?此操作不可恢复', '提示', { type: 'warning' })
const res = await deleteShop(this.shop.id)
const { value } = await this.$prompt(
'删除店铺将不可恢复,请输入 6 位谷歌验证码确认删除',
'安全验证',
{
confirmButtonText: '确认删除',
cancelButtonText: '取消',
type: 'warning',
inputPlaceholder: '6位数字验证码',
inputPattern: /^\d{6}$/,
inputErrorMessage: '谷歌验证码必须是6位数字'
}
)
const gCode = String(value || '').trim()
if (!/^\d{6}$/.test(gCode)) {
this.$message.warning('谷歌验证码必须是6位数字')
return
}
const res = await deleteShop(this.shop.id, gCode)
if (res && (res.code === 0 || res.code === 200)) {
this.$message({
message: '删除成功',
@@ -1074,6 +1209,51 @@ export default {
/* 全局弹窗宽度微调(仅当前页面生效)*/
.el-dialog__body .row { margin-bottom: 12px; }
/* 双重验证拦截弹窗 - 轻渐变美化(仅当前页面生效) */
.google-2fa-guard-dialog {
border-radius: 12px;
overflow: hidden;
}
.google-2fa-guard-dialog .el-message-box__header {
/* 与导航按钮同色系:#667eea -> #764ba2降低透明度让其更淡 */
background: linear-gradient(135deg, rgba(102, 126, 234, 0.16), rgba(118, 75, 162, 0.10));
border-bottom: 1px solid rgba(102, 126, 234, 0.10);
padding: 14px 16px 10px;
}
.google-2fa-guard-dialog .el-message-box__title {
font-weight: 700;
color: #1f2d3d;
}
.google-2fa-guard-dialog .el-message-box__content {
padding: 14px 18px 6px;
}
.google-2fa-guard-dialog .el-message-box__message {
color: #374151;
line-height: 1.7;
}
.google-2fa-guard-dialog .google-2fa-guard__title {
font-size: 15px;
font-weight: 700;
color: #111827;
margin-bottom: 6px;
}
.google-2fa-guard-dialog .google-2fa-guard__desc {
font-size: 13px;
color: #4b5563;
}
.google-2fa-guard-dialog .el-message-box__btns {
padding: 10px 16px 14px;
}
.google-2fa-guard-dialog .el-button--primary {
border: none;
/* 与导航按钮一致的紫色渐变 */
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.google-2fa-guard-dialog .el-button--primary:hover,
.google-2fa-guard-dialog .el-button--primary:focus {
filter: brightness(1.02);
}
/* 弹窗表单统一对齐与留白优化 */
.el-dialog__body .row {
display: grid;