feat: 新增vm支付
This commit is contained in:
parent
4ee2c02daf
commit
28b5702c56
|
|
@ -73,11 +73,140 @@
|
||||||
</mf-button>
|
</mf-button>
|
||||||
</div>
|
</div>
|
||||||
</mf-dialog>
|
</mf-dialog>
|
||||||
|
|
||||||
|
<!-- VM支付信用卡信息对话框 -->
|
||||||
|
<mf-dialog
|
||||||
|
:visible="vmCardVisible"
|
||||||
|
modal-class="vm-card-dialog"
|
||||||
|
class="vm-card-dialog-wrapper"
|
||||||
|
:title="$t('common.vmCardInfo')"
|
||||||
|
hideTitle
|
||||||
|
:footer="false"
|
||||||
|
unmountOnClose
|
||||||
|
@cancel="cancelVmCard">
|
||||||
|
<div class="vm-card-close">
|
||||||
|
<mf-icon
|
||||||
|
value="icon-close"
|
||||||
|
@click="cancelVmCard" />
|
||||||
|
</div>
|
||||||
|
<div class="vm-card-title">
|
||||||
|
{{ $t('common.vmCardInfo') }}
|
||||||
|
</div>
|
||||||
|
<a-form
|
||||||
|
ref="vmCardFormRef"
|
||||||
|
:model="vmCardForm"
|
||||||
|
:rules="vmCardRules"
|
||||||
|
layout="vertical"
|
||||||
|
class="vm-card-form">
|
||||||
|
<a-form-item
|
||||||
|
:label="$t('common.cardNumber')"
|
||||||
|
field="number">
|
||||||
|
<a-input
|
||||||
|
v-model="vmCardForm.number"
|
||||||
|
:placeholder="$t('common.cardNumberPlaceholder')"
|
||||||
|
:max-length="50" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:label="$t('common.cvc')"
|
||||||
|
field="cvc">
|
||||||
|
<a-input
|
||||||
|
v-model="vmCardForm.cvc"
|
||||||
|
:placeholder="$t('common.cvcPlaceholder')"
|
||||||
|
:max-length="3"
|
||||||
|
type="password" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item
|
||||||
|
:label="$t('common.expYear')"
|
||||||
|
field="expYear">
|
||||||
|
<a-input
|
||||||
|
v-model="vmCardForm.expYear"
|
||||||
|
:placeholder="$t('common.expYearPlaceholder')"
|
||||||
|
:max-length="4" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item
|
||||||
|
:label="$t('common.expMonth')"
|
||||||
|
field="expMonth">
|
||||||
|
<a-select
|
||||||
|
v-model="vmCardForm.expMonth"
|
||||||
|
:placeholder="$t('common.expMonthPlaceholder')">
|
||||||
|
<a-option
|
||||||
|
v-for="month in monthOptions"
|
||||||
|
:key="month.value"
|
||||||
|
:value="month.value">
|
||||||
|
{{ month.label }}
|
||||||
|
</a-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<a-form-item
|
||||||
|
:label="$t('common.email')"
|
||||||
|
field="email">
|
||||||
|
<a-input
|
||||||
|
v-model="vmCardForm.email"
|
||||||
|
:placeholder="$t('common.emailPlaceholder')"
|
||||||
|
:max-length="30" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:label="$t('common.firstName')"
|
||||||
|
field="firstName">
|
||||||
|
<a-input
|
||||||
|
v-model="vmCardForm.firstName"
|
||||||
|
:placeholder="$t('common.firstNamePlaceholder')"
|
||||||
|
:max-length="30" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:label="$t('common.lastName')"
|
||||||
|
field="lastName">
|
||||||
|
<a-input
|
||||||
|
v-model="vmCardForm.lastName"
|
||||||
|
:placeholder="$t('common.lastNamePlaceholder')"
|
||||||
|
:max-length="30" />
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
:label="$t('common.country')"
|
||||||
|
field="country">
|
||||||
|
<a-select
|
||||||
|
v-model="vmCardForm.country"
|
||||||
|
:placeholder="$t('common.countryPlaceholder')"
|
||||||
|
show-search
|
||||||
|
:filter-option="filterCountry">
|
||||||
|
<a-option
|
||||||
|
v-for="country in countryList"
|
||||||
|
:key="country.code"
|
||||||
|
:value="country.code">
|
||||||
|
{{ getCountryName(country) }} ({{ country.code }})
|
||||||
|
</a-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
<div class="vm-card-submit">
|
||||||
|
<mf-button
|
||||||
|
size="large"
|
||||||
|
type="primary"
|
||||||
|
:loading="vmCardLoading"
|
||||||
|
@click="submitVmCard">
|
||||||
|
{{ $t('common.submit') }}
|
||||||
|
</mf-button>
|
||||||
|
<mf-button
|
||||||
|
size="large"
|
||||||
|
@click="cancelVmCard">
|
||||||
|
{{ $t('common.cancel') }}
|
||||||
|
</mf-button>
|
||||||
|
</div>
|
||||||
|
</mf-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { v4 } from 'uuid'
|
import { v4 } from 'uuid'
|
||||||
|
import { countryList } from '@/utils/countryCodes'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'mf-recharge-pc',
|
name: 'mf-recharge-pc',
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -90,20 +219,100 @@ export default {
|
||||||
rechargeRemark: '',
|
rechargeRemark: '',
|
||||||
payVisible: false,
|
payVisible: false,
|
||||||
orderNo: null,
|
orderNo: null,
|
||||||
showPay: import.meta.env.VITE_SHOW_PAY == "SUCCESS"
|
showPay: import.meta.env.VITE_SHOW_PAY == "SUCCESS",
|
||||||
|
// VM支付相关
|
||||||
|
vmCardVisible: false,
|
||||||
|
vmCardLoading: false,
|
||||||
|
currentGearId: null,
|
||||||
|
vmCardForm: {
|
||||||
|
number: '',
|
||||||
|
cvc: '',
|
||||||
|
expYear: '',
|
||||||
|
expMonth: '',
|
||||||
|
email: '',
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
|
country: ''
|
||||||
|
},
|
||||||
|
vmCardRules: {},
|
||||||
|
monthOptions: [
|
||||||
|
{ value: '01', label: '01' },
|
||||||
|
{ value: '02', label: '02' },
|
||||||
|
{ value: '03', label: '03' },
|
||||||
|
{ value: '04', label: '04' },
|
||||||
|
{ value: '05', label: '05' },
|
||||||
|
{ value: '06', label: '06' },
|
||||||
|
{ value: '07', label: '07' },
|
||||||
|
{ value: '08', label: '08' },
|
||||||
|
{ value: '09', label: '09' },
|
||||||
|
{ value: '10', label: '10' },
|
||||||
|
{ value: '11', label: '11' },
|
||||||
|
{ value: '12', label: '12' }
|
||||||
|
],
|
||||||
|
countryList: countryList
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
rechargeId: [String, Number],
|
rechargeId: [String, Number],
|
||||||
apiUrl: String
|
apiUrl: String
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['lang']),
|
||||||
|
isVmPay() {
|
||||||
|
// 判断是否是VM支付,根据apiUrl判断
|
||||||
|
return this.apiUrl && (this.apiUrl.includes('vm') || this.apiUrl.includes('vm-pay'))
|
||||||
|
}
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
rechargeId(val) {
|
rechargeId(val) {
|
||||||
if (!val) return
|
if (!val) return
|
||||||
this.getGiftInfo()
|
this.getGiftInfo()
|
||||||
|
},
|
||||||
|
lang() {
|
||||||
|
// 语言切换时更新验证规则
|
||||||
|
this.initVmCardRules()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.initVmCardRules()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 初始化VM卡表单验证规则
|
||||||
|
initVmCardRules() {
|
||||||
|
this.vmCardRules = {
|
||||||
|
number: [
|
||||||
|
{ required: true, message: this.$t('common.cardNumberRequired') || '请输入信用卡卡号', trigger: 'blur' },
|
||||||
|
{ pattern: /^\d{13,19}$/, message: this.$t('common.cardNumberInvalid') || '信用卡卡号格式不正确', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
cvc: [
|
||||||
|
{ required: true, message: this.$t('common.cvcRequired') || '请输入CVC', trigger: 'blur' },
|
||||||
|
{ pattern: /^\d{3}$/, message: this.$t('common.cvcInvalid') || 'CVC必须是3位数字', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
expYear: [
|
||||||
|
{ required: true, message: this.$t('common.expYearRequired') || '请输入过期年份', trigger: 'blur' },
|
||||||
|
{ pattern: /^\d{4}$/, message: this.$t('common.expYearInvalid') || '年份必须是4位数字', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
expMonth: [
|
||||||
|
{ required: true, message: this.$t('common.expMonthRequired') || '请选择过期月份', trigger: 'change' }
|
||||||
|
],
|
||||||
|
email: [
|
||||||
|
{ required: true, message: this.$t('common.emailRequired') || '请输入邮箱', trigger: 'blur' },
|
||||||
|
{ type: 'email', message: this.$t('common.emailInvalid') || '邮箱格式不正确', trigger: 'blur' },
|
||||||
|
{ max: 30, message: this.$t('common.emailMaxLength') || '邮箱不能超过30个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
firstName: [
|
||||||
|
{ required: true, message: this.$t('common.firstNameRequired') || '请输入持卡人名字', trigger: 'blur' },
|
||||||
|
{ max: 30, message: this.$t('common.firstNameMaxLength') || '名字不能超过30个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
lastName: [
|
||||||
|
{ required: true, message: this.$t('common.lastNameRequired') || '请输入持卡人姓氏', trigger: 'blur' },
|
||||||
|
{ max: 30, message: this.$t('common.lastNameMaxLength') || '姓氏不能超过30个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
country: [
|
||||||
|
{ required: true, message: this.$t('common.countryRequired') || '请选择国家', trigger: 'change' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
cancelPay() {
|
cancelPay() {
|
||||||
this.orderNo = null
|
this.orderNo = null
|
||||||
this.payVisible = false
|
this.payVisible = false
|
||||||
|
|
@ -167,7 +376,107 @@ export default {
|
||||||
},
|
},
|
||||||
ok() {
|
ok() {
|
||||||
let selectedItem = this.dataList[this.selectedIndex]
|
let selectedItem = this.dataList[this.selectedIndex]
|
||||||
|
// 如果是VM支付,弹出信用卡信息对话框
|
||||||
|
if (this.isVmPay) {
|
||||||
|
this.currentGearId = selectedItem.id
|
||||||
|
this.vmCardVisible = true
|
||||||
|
this.resetVmCardForm()
|
||||||
|
} else {
|
||||||
this.doRecharge(selectedItem.id)
|
this.doRecharge(selectedItem.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 重置VM卡表单
|
||||||
|
resetVmCardForm() {
|
||||||
|
this.vmCardForm = {
|
||||||
|
number: '',
|
||||||
|
cvc: '',
|
||||||
|
expYear: '',
|
||||||
|
expMonth: '',
|
||||||
|
email: '',
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
|
country: ''
|
||||||
|
}
|
||||||
|
if (this.$refs.vmCardFormRef) {
|
||||||
|
this.$refs.vmCardFormRef.resetFields()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 取消VM卡对话框
|
||||||
|
cancelVmCard() {
|
||||||
|
this.vmCardVisible = false
|
||||||
|
this.resetVmCardForm()
|
||||||
|
},
|
||||||
|
// 提交VM卡信息
|
||||||
|
async submitVmCard() {
|
||||||
|
if (!this.$refs.vmCardFormRef) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.$refs.vmCardFormRef.validate()
|
||||||
|
this.vmCardLoading = true
|
||||||
|
|
||||||
|
// 调用VM支付接口
|
||||||
|
this.$axios({
|
||||||
|
url: '/api/pay/vm-pay',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
gearId: this.currentGearId,
|
||||||
|
vmCardInfo: {
|
||||||
|
number: this.vmCardForm.number,
|
||||||
|
cvc: this.vmCardForm.cvc,
|
||||||
|
expYear: this.vmCardForm.expYear,
|
||||||
|
expMonth: this.vmCardForm.expMonth,
|
||||||
|
email: this.vmCardForm.email,
|
||||||
|
firstName: this.vmCardForm.firstName,
|
||||||
|
lastName: this.vmCardForm.lastName,
|
||||||
|
country: this.vmCardForm.country
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
this.vmCardLoading = false
|
||||||
|
if (res.code == 200) {
|
||||||
|
this.$message.success(this.$t('common.rechargeSuccessfully') || '支付请求提交成功')
|
||||||
|
this.vmCardVisible = false
|
||||||
|
this.resetVmCardForm()
|
||||||
|
// 获取支付URL并跳转
|
||||||
|
if (res.data?.payUrl) {
|
||||||
|
window.open(res.data.payUrl)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$message.error(res.msg || this.$t('common.rechargeFailed') || '支付请求失败')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.vmCardLoading = false
|
||||||
|
if (err.response && err.response.data && err.response.data.msg) {
|
||||||
|
this.$message.error(err.response.data.msg)
|
||||||
|
} else {
|
||||||
|
this.$message.error(this.$t('common.rechargeFailed') || '支付请求失败,请稍后重试')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
// 表单验证失败
|
||||||
|
console.error('表单验证失败:', error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 获取国家名称(根据当前语言)
|
||||||
|
getCountryName(country) {
|
||||||
|
if (!country) return ''
|
||||||
|
// 如果是英文,显示英文名称
|
||||||
|
if (this.lang === 'en_US') {
|
||||||
|
return country.nameEn || country.name
|
||||||
|
}
|
||||||
|
// 默认显示中文名称
|
||||||
|
return country.name
|
||||||
|
},
|
||||||
|
// 国家下拉框搜索过滤
|
||||||
|
filterCountry(inputValue, option) {
|
||||||
|
const country = this.countryList.find(c => c.code === option.value)
|
||||||
|
if (!country) return false
|
||||||
|
const name = this.getCountryName(country).toLowerCase()
|
||||||
|
const code = country.code.toLowerCase()
|
||||||
|
const searchValue = inputValue.toLowerCase()
|
||||||
|
return name.includes(searchValue) || code.includes(searchValue)
|
||||||
},
|
},
|
||||||
doRecharge(gearId) {
|
doRecharge(gearId) {
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
|
@ -311,9 +620,121 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vm-card-dialog {
|
||||||
|
border-radius: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: linear-gradient(
|
||||||
|
0deg,
|
||||||
|
rgba(39, 20, 51, 0.7) 0%,
|
||||||
|
rgba(230, 33, 122, 0.7) 49%
|
||||||
|
);
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #e6217a;
|
||||||
|
width: 600px;
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
top: 50% !important;
|
||||||
|
transform: translateY(-50%) !important;
|
||||||
|
&-wrapper {
|
||||||
|
.arco-modal-mask {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.arco-modal-body {
|
||||||
|
padding: 24px 30px 30px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vm-card-close {
|
||||||
|
position: absolute;
|
||||||
|
right: 12px;
|
||||||
|
top: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #fff;
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.mf-icon {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vm-card-title {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #ffffff;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vm-card-form {
|
||||||
|
:deep(.arco-form-item-label) {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-input-wrapper),
|
||||||
|
:deep(.arco-select-view-single) {
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid rgba(#ffffff, 0.3);
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.arco-input-focus,
|
||||||
|
&.arco-select-view-focus {
|
||||||
|
border-color: rgb(var(--primary-6));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-input),
|
||||||
|
:deep(.arco-select-view-value) {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-input::placeholder),
|
||||||
|
:deep(.arco-select-placeholder) {
|
||||||
|
color: rgba(#fff, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-select-dropdown) {
|
||||||
|
background-color: rgba(39, 20, 51, 0.95);
|
||||||
|
border: 1px solid #e6217a;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.arco-select-option) {
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(230, 33, 122, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.arco-select-option-selected {
|
||||||
|
background-color: rgba(230, 33, 122, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vm-card-submit {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 30px;
|
||||||
|
.mf-button {
|
||||||
|
width: 160px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.mf-recharge-pc {
|
.mf-recharge-pc {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: wrap;
|
flex-flow: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
&-tips {
|
&-tips {
|
||||||
color: #999;
|
color: #999;
|
||||||
|
|
@ -328,52 +749,106 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 14px;
|
||||||
.mf-button {
|
.mf-button {
|
||||||
width: 160px;
|
width: 160px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
margin: 0 14px;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-item {
|
&-item {
|
||||||
width: calc(25% - 20px);
|
flex: 1 1 calc(25% - 10px);
|
||||||
|
min-width: 200px;
|
||||||
|
max-width: 100%;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
margin: 0 10px 10px 10px;
|
|
||||||
background-color: #1f1f1f;
|
background-color: #1f1f1f;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: 20px;
|
padding: clamp(12px, 2vw, 20px);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
background-color: rgb(var(--primary-6));
|
background-color: rgb(var(--primary-6));
|
||||||
}
|
}
|
||||||
|
|
||||||
&-title {
|
&-title {
|
||||||
font-size: 30px;
|
font-size: clamp(16px, 2.5vw, 30px);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
line-height: 1.3;
|
||||||
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.arco-divider {
|
.arco-divider {
|
||||||
border-color: rgba(#fff, 0.3);
|
border-color: rgba(#fff, 0.3);
|
||||||
|
margin: clamp(8px, 1.5vw, 12px) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-value {
|
&-value {
|
||||||
color: 14px;
|
font-size: clamp(12px, 1.5vw, 14px);
|
||||||
|
line-height: 1.5;
|
||||||
span {
|
span {
|
||||||
color: rgb(var(--primary));
|
color: rgb(var(--primary));
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media (max-width: 576px) {
|
|
||||||
|
// 大屏幕 (≥1400px)
|
||||||
|
@media (min-width: 1400px) {
|
||||||
.mf-recharge-pc {
|
.mf-recharge-pc {
|
||||||
&-item {
|
&-item {
|
||||||
width: calc(50% - 20px);
|
flex: 1 1 calc(20% - 10px);
|
||||||
&-title {
|
min-width: 220px;
|
||||||
font-size: 20px;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 中等屏幕 (768px - 1199px)
|
||||||
|
@media (min-width: 768px) and (max-width: 1199px) {
|
||||||
|
.mf-recharge-pc {
|
||||||
|
&-item {
|
||||||
|
flex: 1 1 calc(33.333% - 10px);
|
||||||
|
min-width: 180px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小屏幕 (576px - 767px)
|
||||||
|
@media (min-width: 576px) and (max-width: 767px) {
|
||||||
|
.mf-recharge-pc {
|
||||||
|
&-item {
|
||||||
|
flex: 1 1 calc(50% - 10px);
|
||||||
|
min-width: 160px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移动端 (≤576px)
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
.mf-recharge-pc {
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
flex: 1 1 calc(50% - 8px);
|
||||||
|
min-width: 140px;
|
||||||
|
padding: 12px;
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
font-size: clamp(14px, 4vw, 18px);
|
||||||
|
}
|
||||||
|
|
||||||
.arco-divider {
|
.arco-divider {
|
||||||
margin: 10px 0;
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-value {
|
||||||
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -381,6 +856,24 @@ export default {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-submit {
|
||||||
|
flex-direction: column;
|
||||||
|
.mf-button {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 超小屏幕 (≤400px)
|
||||||
|
@media (max-width: 400px) {
|
||||||
|
.mf-recharge-pc {
|
||||||
|
&-item {
|
||||||
|
flex: 1 1 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,6 @@ export default {
|
||||||
forgotPassword: 'Forgot password',
|
forgotPassword: 'Forgot password',
|
||||||
registerAccount: 'Register Account',
|
registerAccount: 'Register Account',
|
||||||
usernamePlaceholder: 'Enter username',
|
usernamePlaceholder: 'Enter username',
|
||||||
emailPlaceholder: 'Enter email',
|
|
||||||
codePlaceholder: 'Enter verification code',
|
codePlaceholder: 'Enter verification code',
|
||||||
confirmPasswordPlaceholder: 'Confirm password',
|
confirmPasswordPlaceholder: 'Confirm password',
|
||||||
backToLogin: 'Back to Login',
|
backToLogin: 'Back to Login',
|
||||||
|
|
@ -142,5 +141,38 @@ export default {
|
||||||
cardName: 'Cardholder Name',
|
cardName: 'Cardholder Name',
|
||||||
cardNoRequired: 'Please enter card number',
|
cardNoRequired: 'Please enter card number',
|
||||||
cardNameRequired: 'Please enter cardholder name',
|
cardNameRequired: 'Please enter cardholder name',
|
||||||
rechargeFailed: 'Recharge failed'
|
rechargeFailed: 'Recharge failed',
|
||||||
|
// VM支付相关
|
||||||
|
vmCardInfo: 'Credit Card Information',
|
||||||
|
cardNumber: 'Card Number',
|
||||||
|
cardNumberPlaceholder: 'Enter card number',
|
||||||
|
cardNumberRequired: 'Please enter card number',
|
||||||
|
cardNumberInvalid: 'Card number must be 13-19 digits',
|
||||||
|
cvc: 'CVC',
|
||||||
|
cvcPlaceholder: 'Enter CVC',
|
||||||
|
cvcRequired: 'Please enter CVC',
|
||||||
|
cvcInvalid: 'CVC must be 3 digits',
|
||||||
|
expYear: 'Expiration Year',
|
||||||
|
expYearPlaceholder: 'Enter expiration year (e.g., 2027)',
|
||||||
|
expYearRequired: 'Please enter expiration year',
|
||||||
|
expYearInvalid: 'Year must be 4 digits',
|
||||||
|
expMonth: 'Expiration Month',
|
||||||
|
expMonthPlaceholder: 'Select expiration month',
|
||||||
|
expMonthRequired: 'Please select expiration month',
|
||||||
|
emailPlaceholder: 'Enter email address',
|
||||||
|
emailRequired: 'Please enter email',
|
||||||
|
emailInvalid: 'Invalid email format',
|
||||||
|
emailMaxLength: 'Email cannot exceed 30 characters',
|
||||||
|
firstName: 'First Name',
|
||||||
|
firstNamePlaceholder: 'Enter first name',
|
||||||
|
firstNameRequired: 'Please enter first name',
|
||||||
|
firstNameMaxLength: 'First name cannot exceed 30 characters',
|
||||||
|
lastName: 'Last Name',
|
||||||
|
lastNamePlaceholder: 'Enter last name',
|
||||||
|
lastNameRequired: 'Please enter last name',
|
||||||
|
lastNameMaxLength: 'Last name cannot exceed 30 characters',
|
||||||
|
country: 'Country',
|
||||||
|
countryPlaceholder: 'Select country',
|
||||||
|
countryRequired: 'Please select country',
|
||||||
|
submit: 'Submit'
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +52,6 @@ export default {
|
||||||
forgotPassword: '忘記密碼',
|
forgotPassword: '忘記密碼',
|
||||||
registerAccount: '註冊帳號',
|
registerAccount: '註冊帳號',
|
||||||
usernamePlaceholder: '請輸入帳號',
|
usernamePlaceholder: '請輸入帳號',
|
||||||
emailPlaceholder: '請輸入郵箱',
|
|
||||||
codePlaceholder: '請輸入驗證碼',
|
codePlaceholder: '請輸入驗證碼',
|
||||||
confirmPasswordPlaceholder: '請再次輸入密碼',
|
confirmPasswordPlaceholder: '請再次輸入密碼',
|
||||||
backToLogin: '返回登入',
|
backToLogin: '返回登入',
|
||||||
|
|
@ -96,7 +95,6 @@ export default {
|
||||||
passwordResetSuccessfully: '密碼重置成功',
|
passwordResetSuccessfully: '密碼重置成功',
|
||||||
rechargeSuccessfully: '充值成功',
|
rechargeSuccessfully: '充值成功',
|
||||||
avatar: '頭像',
|
avatar: '頭像',
|
||||||
email: '郵箱',
|
|
||||||
input: '請輸入',
|
input: '請輸入',
|
||||||
save: '保存',
|
save: '保存',
|
||||||
editEmail: '修改郵箱',
|
editEmail: '修改郵箱',
|
||||||
|
|
@ -104,7 +102,6 @@ export default {
|
||||||
updateAvatarSuccessfully: '頭像更新成功',
|
updateAvatarSuccessfully: '頭像更新成功',
|
||||||
balenceLow: '您的餘額不足,請充值',
|
balenceLow: '您的餘額不足,請充值',
|
||||||
confirm: '確定',
|
confirm: '確定',
|
||||||
cancel: '取消',
|
|
||||||
createFailed: '生成失敗,餘額已退回',
|
createFailed: '生成失敗,餘額已退回',
|
||||||
notice: '提示',
|
notice: '提示',
|
||||||
oldPasswordPlaceholder: '請輸入舊的密碼',
|
oldPasswordPlaceholder: '請輸入舊的密碼',
|
||||||
|
|
@ -146,5 +143,40 @@ export default {
|
||||||
cardName: '銀行卡姓名',
|
cardName: '銀行卡姓名',
|
||||||
cardNoRequired: '請輸入銀行卡號',
|
cardNoRequired: '請輸入銀行卡號',
|
||||||
cardNameRequired: '請輸入銀行卡姓名',
|
cardNameRequired: '請輸入銀行卡姓名',
|
||||||
rechargeFailed: '充值失敗'
|
rechargeFailed: '充值失敗',
|
||||||
|
// VM支付相關
|
||||||
|
vmCardInfo: '信用卡信息',
|
||||||
|
cardNumber: '信用卡卡號',
|
||||||
|
cardNumberPlaceholder: '請輸入信用卡卡號',
|
||||||
|
cardNumberRequired: '請輸入信用卡卡號',
|
||||||
|
cardNumberInvalid: '信用卡卡號必須是13-19位數字',
|
||||||
|
cvc: 'CVC',
|
||||||
|
cvcPlaceholder: '請輸入CVC',
|
||||||
|
cvcRequired: '請輸入CVC',
|
||||||
|
cvcInvalid: 'CVC必須是3位數字',
|
||||||
|
expYear: '過期年',
|
||||||
|
expYearPlaceholder: '請輸入過期年份(例如:2027)',
|
||||||
|
expYearRequired: '請輸入過期年份',
|
||||||
|
expYearInvalid: '年份必須是4位數字',
|
||||||
|
expMonth: '過期月',
|
||||||
|
expMonthPlaceholder: '請選擇過期月份',
|
||||||
|
expMonthRequired: '請選擇過期月份',
|
||||||
|
email: '郵箱',
|
||||||
|
emailPlaceholder: '請輸入郵箱地址',
|
||||||
|
emailRequired: '請輸入郵箱',
|
||||||
|
emailInvalid: '郵箱格式不正確',
|
||||||
|
emailMaxLength: '郵箱不能超過30個字符',
|
||||||
|
firstName: '持卡人名字',
|
||||||
|
firstNamePlaceholder: '請輸入持卡人名字',
|
||||||
|
firstNameRequired: '請輸入持卡人名字',
|
||||||
|
firstNameMaxLength: '名字不能超過30個字符',
|
||||||
|
lastName: '持卡人姓氏',
|
||||||
|
lastNamePlaceholder: '請輸入持卡人姓氏',
|
||||||
|
lastNameRequired: '請輸入持卡人姓氏',
|
||||||
|
lastNameMaxLength: '姓氏不能超過30個字符',
|
||||||
|
country: '國家',
|
||||||
|
countryPlaceholder: '請選擇國家',
|
||||||
|
countryRequired: '請選擇國家',
|
||||||
|
submit: '提交',
|
||||||
|
cancel: '取消'
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
/**
|
||||||
|
* ISO 3166-1 alpha-2 国家代码列表
|
||||||
|
* 用于VM支付的国家选择下拉框
|
||||||
|
*/
|
||||||
|
export const countryList = [
|
||||||
|
{ code: 'US', name: '美国', nameEn: 'United States' },
|
||||||
|
{ code: 'GB', name: '英国', nameEn: 'United Kingdom' },
|
||||||
|
{ code: 'CA', name: '加拿大', nameEn: 'Canada' },
|
||||||
|
{ code: 'AU', name: '澳大利亚', nameEn: 'Australia' },
|
||||||
|
{ code: 'DE', name: '德国', nameEn: 'Germany' },
|
||||||
|
{ code: 'FR', name: '法国', nameEn: 'France' },
|
||||||
|
{ code: 'IT', name: '意大利', nameEn: 'Italy' },
|
||||||
|
{ code: 'ES', name: '西班牙', nameEn: 'Spain' },
|
||||||
|
{ code: 'NL', name: '荷兰', nameEn: 'Netherlands' },
|
||||||
|
{ code: 'BE', name: '比利时', nameEn: 'Belgium' },
|
||||||
|
{ code: 'CH', name: '瑞士', nameEn: 'Switzerland' },
|
||||||
|
{ code: 'AT', name: '奥地利', nameEn: 'Austria' },
|
||||||
|
{ code: 'SE', name: '瑞典', nameEn: 'Sweden' },
|
||||||
|
{ code: 'NO', name: '挪威', nameEn: 'Norway' },
|
||||||
|
{ code: 'DK', name: '丹麦', nameEn: 'Denmark' },
|
||||||
|
{ code: 'FI', name: '芬兰', nameEn: 'Finland' },
|
||||||
|
{ code: 'PL', name: '波兰', nameEn: 'Poland' },
|
||||||
|
{ code: 'CZ', name: '捷克', nameEn: 'Czech Republic' },
|
||||||
|
{ code: 'IE', name: '爱尔兰', nameEn: 'Ireland' },
|
||||||
|
{ code: 'PT', name: '葡萄牙', nameEn: 'Portugal' },
|
||||||
|
{ code: 'GR', name: '希腊', nameEn: 'Greece' },
|
||||||
|
{ code: 'JP', name: '日本', nameEn: 'Japan' },
|
||||||
|
{ code: 'KR', name: '韩国', nameEn: 'South Korea' },
|
||||||
|
{ code: 'CN', name: '中国', nameEn: 'China' },
|
||||||
|
{ code: 'HK', name: '香港', nameEn: 'Hong Kong' },
|
||||||
|
{ code: 'SG', name: '新加坡', nameEn: 'Singapore' },
|
||||||
|
{ code: 'MY', name: '马来西亚', nameEn: 'Malaysia' },
|
||||||
|
{ code: 'TH', name: '泰国', nameEn: 'Thailand' },
|
||||||
|
{ code: 'PH', name: '菲律宾', nameEn: 'Philippines' },
|
||||||
|
{ code: 'ID', name: '印度尼西亚', nameEn: 'Indonesia' },
|
||||||
|
{ code: 'IN', name: '印度', nameEn: 'India' },
|
||||||
|
{ code: 'BR', name: '巴西', nameEn: 'Brazil' },
|
||||||
|
{ code: 'MX', name: '墨西哥', nameEn: 'Mexico' },
|
||||||
|
{ code: 'AR', name: '阿根廷', nameEn: 'Argentina' },
|
||||||
|
{ code: 'CL', name: '智利', nameEn: 'Chile' },
|
||||||
|
{ code: 'CO', name: '哥伦比亚', nameEn: 'Colombia' },
|
||||||
|
{ code: 'PE', name: '秘鲁', nameEn: 'Peru' },
|
||||||
|
{ code: 'ZA', name: '南非', nameEn: 'South Africa' },
|
||||||
|
{ code: 'NZ', name: '新西兰', nameEn: 'New Zealand' },
|
||||||
|
{ code: 'AE', name: '阿联酋', nameEn: 'United Arab Emirates' },
|
||||||
|
{ code: 'SA', name: '沙特阿拉伯', nameEn: 'Saudi Arabia' },
|
||||||
|
{ code: 'IL', name: '以色列', nameEn: 'Israel' },
|
||||||
|
{ code: 'TR', name: '土耳其', nameEn: 'Turkey' },
|
||||||
|
{ code: 'RU', name: '俄罗斯', nameEn: 'Russia' },
|
||||||
|
{ code: 'UA', name: '乌克兰', nameEn: 'Ukraine' },
|
||||||
|
{ code: 'RO', name: '罗马尼亚', nameEn: 'Romania' },
|
||||||
|
{ code: 'HU', name: '匈牙利', nameEn: 'Hungary' },
|
||||||
|
{ code: 'BG', name: '保加利亚', nameEn: 'Bulgaria' },
|
||||||
|
{ code: 'HR', name: '克罗地亚', nameEn: 'Croatia' },
|
||||||
|
{ code: 'SK', name: '斯洛伐克', nameEn: 'Slovakia' },
|
||||||
|
{ code: 'SI', name: '斯洛文尼亚', nameEn: 'Slovenia' },
|
||||||
|
{ code: 'EE', name: '爱沙尼亚', nameEn: 'Estonia' },
|
||||||
|
{ code: 'LV', name: '拉脱维亚', nameEn: 'Latvia' },
|
||||||
|
{ code: 'LT', name: '立陶宛', nameEn: 'Lithuania' },
|
||||||
|
{ code: 'IS', name: '冰岛', nameEn: 'Iceland' },
|
||||||
|
{ code: 'LU', name: '卢森堡', nameEn: 'Luxembourg' },
|
||||||
|
{ code: 'MT', name: '马耳他', nameEn: 'Malta' },
|
||||||
|
{ code: 'CY', name: '塞浦路斯', nameEn: 'Cyprus' },
|
||||||
|
{ code: 'TW', name: '台湾', nameEn: 'Taiwan' },
|
||||||
|
{ code: 'MO', name: '澳门', nameEn: 'Macau' },
|
||||||
|
{ code: 'VN', name: '越南', nameEn: 'Vietnam' },
|
||||||
|
{ code: 'MM', name: '缅甸', nameEn: 'Myanmar' },
|
||||||
|
{ code: 'KH', name: '柬埔寨', nameEn: 'Cambodia' },
|
||||||
|
{ code: 'LA', name: '老挝', nameEn: 'Laos' },
|
||||||
|
{ code: 'BN', name: '文莱', nameEn: 'Brunei' },
|
||||||
|
{ code: 'BD', name: '孟加拉国', nameEn: 'Bangladesh' },
|
||||||
|
{ code: 'PK', name: '巴基斯坦', nameEn: 'Pakistan' },
|
||||||
|
{ code: 'LK', name: '斯里兰卡', nameEn: 'Sri Lanka' },
|
||||||
|
{ code: 'NP', name: '尼泊尔', nameEn: 'Nepal' }
|
||||||
|
]
|
||||||
|
|
@ -180,7 +180,7 @@ const showRecharge = () => {
|
||||||
|
|
||||||
&-left {
|
&-left {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 200px;
|
width: clamp(160px, 12vw, 200px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
|
@ -200,13 +200,14 @@ const showRecharge = () => {
|
||||||
|
|
||||||
&-right {
|
&-right {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
padding: 0 60px 60px 20px;
|
padding: 0 clamp(12px, 4vw, 60px) clamp(20px, 4vw, 60px) clamp(12px, 2vw, 20px);
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
min-width: 0; // 防止 flex 子元素溢出
|
||||||
|
|
||||||
&-banner {
|
&-banner {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
aspect-ratio: 6 / 1;
|
aspect-ratio: 6 / 1;
|
||||||
margin-bottom: 40px;
|
margin-bottom: clamp(20px, 3vw, 40px);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
@ -303,6 +304,20 @@ const showRecharge = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 平板和中等屏幕 (768px - 1024px)
|
||||||
|
@media (min-width: 768px) and (max-width: 1024px) {
|
||||||
|
.recharge {
|
||||||
|
&-left {
|
||||||
|
width: clamp(140px, 15vw, 180px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-right {
|
||||||
|
padding: 0 clamp(16px, 3vw, 40px) clamp(20px, 3vw, 40px) clamp(12px, 2vw, 20px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移动端 (≤576px)
|
||||||
@media (max-width: 576px) {
|
@media (max-width: 576px) {
|
||||||
.recharge {
|
.recharge {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -350,18 +365,6 @@ const showRecharge = () => {
|
||||||
height: 160px;
|
height: 160px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.mf-recharge-pc) {
|
|
||||||
&-item {
|
|
||||||
width: calc(50% - 20px);
|
|
||||||
&-title {
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
.arco-divider {
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue