293 lines
7.8 KiB
Vue
293 lines
7.8 KiB
Vue
<script setup lang="ts">
|
|
import { ref, computed, onMounted, onUnmounted } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { submitOrder } from '@/service/api/auth';
|
|
import { aliPayPcPay, aliPayWapPay, wxPayScanCode } from '@/service/api/payment';
|
|
import { message } from 'ant-design-vue';
|
|
import { useRouterPush } from '@/hooks/common/router';
|
|
import type { Ref } from 'vue';
|
|
import OrderConfirmModal from '@/components/order-confirm/orderConfirmModal.vue';
|
|
import { useAppStore } from '@/store/modules/app';
|
|
|
|
defineOptions({
|
|
name: 'BalanceRecharge'
|
|
});
|
|
|
|
const { t } = useI18n();
|
|
const { routerPushByKey } = useRouterPush();
|
|
const appStore = useAppStore();
|
|
|
|
interface RechargeOption {
|
|
amount: number;
|
|
displayAmount: string;
|
|
price: number;
|
|
}
|
|
|
|
const customAmount = ref<string | number | undefined>(undefined);
|
|
const selectedAmount = ref<number | null>(null);
|
|
const isCustomMode = ref<boolean>(false);
|
|
|
|
const rechargeOptions: Ref<RechargeOption[]> = ref([
|
|
{ amount: 10, displayAmount: `${t('page.carddata.money')}10`, price: 10.00 },
|
|
{ amount: 20, displayAmount: `${t('page.carddata.money')}20`, price: 20.00 },
|
|
{ amount: 30, displayAmount: `${t('page.carddata.money')}30`, price: 30.00 },
|
|
{ amount: 50, displayAmount: `${t('page.carddata.money')}50`, price: 50.00 },
|
|
{ amount: 100, displayAmount: `${t('page.carddata.money')}100`, price: 100.00 },
|
|
{ amount: 200, displayAmount: `${t('page.carddata.money')}200`, price: 200.00 },
|
|
]);
|
|
|
|
const paymentAmount = computed(() => {
|
|
if (customAmount.value !== undefined && customAmount.value !== '') {
|
|
return Number(customAmount.value);
|
|
}
|
|
return selectedAmount.value || 0;
|
|
});
|
|
|
|
const handleOptionSelect = (amount: number) => {
|
|
isCustomMode.value = false;
|
|
selectedAmount.value = amount;
|
|
customAmount.value = undefined;
|
|
};
|
|
|
|
const handleCustomMode = () => {
|
|
isCustomMode.value = true;
|
|
selectedAmount.value = null;
|
|
};
|
|
|
|
const handleCustomAmount = (value: string | number | undefined) => {
|
|
customAmount.value = value;
|
|
};
|
|
|
|
// 添加点击外部关闭自定义输入的处理
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
const target = event.target as HTMLElement;
|
|
if (isCustomMode.value &&
|
|
!target?.closest('.special-option') &&
|
|
customAmount.value === undefined) {
|
|
isCustomMode.value = false;
|
|
}
|
|
};
|
|
|
|
// 创建一个函数来处理 blur 事件
|
|
const handleBlur = () => {
|
|
if (customAmount.value === undefined || customAmount.value === '') {
|
|
isCustomMode.value = false;
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
document.addEventListener('click', handleClickOutside);
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
document.removeEventListener('click', handleClickOutside);
|
|
});
|
|
|
|
// 添加订单确认弹窗相关状态
|
|
const showOrderModal = ref(false);
|
|
const currentOrderInfo = ref({
|
|
orderId: '',
|
|
orderType: 1, // 1 表示余额充值
|
|
orderAmount: 0
|
|
});
|
|
|
|
// 修改充值处理方法
|
|
const handleRecharge = async () => {
|
|
// 验证金额
|
|
if (!paymentAmount.value || paymentAmount.value <= 0) {
|
|
message.error(t('page.carddata.truemoney'));
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const orderRes = await submitOrder({
|
|
type: 1,
|
|
orderAmount: paymentAmount.value
|
|
});
|
|
|
|
// 更新订单信息并显示弹窗
|
|
currentOrderInfo.value = {
|
|
orderId: orderRes.data,
|
|
orderType: 1,
|
|
orderAmount: paymentAmount.value
|
|
};
|
|
showOrderModal.value = true;
|
|
} catch (error) {
|
|
// message.error(t('page.carddata.falseorder'));
|
|
// console.error('Failed to create order:', error);
|
|
}
|
|
};
|
|
|
|
// 修改支付处理方法
|
|
const handlePaymentConfirm = async (paymentMethod: 'alipay' | 'wxpay') => {
|
|
try {
|
|
if (paymentMethod === 'alipay') {
|
|
// 区分手机端和pc端支付
|
|
let res;
|
|
if (appStore.isMobile) {
|
|
res = await aliPayWapPay({ orderId: currentOrderInfo.value.orderId });
|
|
} else {
|
|
res = await aliPayPcPay({ orderId: currentOrderInfo.value.orderId });
|
|
}
|
|
|
|
const div = document.createElement('div');
|
|
div.innerHTML = res;
|
|
document.body.appendChild(div);
|
|
document.forms['punchout_form'].submit();
|
|
div.remove();
|
|
} else {
|
|
// 添加微信支付处理
|
|
const res = await wxPayScanCode({ orderId: currentOrderInfo.value.orderId });
|
|
routerPushByKey('billing_wxpay', {
|
|
query: {
|
|
url: res.data,
|
|
orderId: currentOrderInfo.value.orderId
|
|
}
|
|
});
|
|
}
|
|
} catch (error) {
|
|
// message.error(t('page.order.paymentFailed'));
|
|
// console.error('Payment failed:', error);
|
|
} finally {
|
|
showOrderModal.value = false;
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="recharge-container p-4">
|
|
<!-- 充值金额选择 -->
|
|
<div class="amount-section mb-6">
|
|
<div class="text-lg font-bold mb-2">{{ t('page.carddata.Rechargeamount') }}</div>
|
|
<div class="grid grid-cols-3 gap-4">
|
|
<div
|
|
v-for="option in rechargeOptions"
|
|
:key="option.amount"
|
|
class="recharge-option cursor-pointer"
|
|
:class="{ 'selected': selectedAmount === option.amount }"
|
|
@click="handleOptionSelect(option.amount)"
|
|
>
|
|
<div class="text-lg font-medium">{{ option.displayAmount }}</div>
|
|
<div class="text-sm text-gray-500">{{ option.price.toFixed(2) }}</div>
|
|
</div>
|
|
|
|
<!-- 自定义充选项 -->
|
|
<div
|
|
class="special-option"
|
|
:class="{ 'selected': isCustomMode }"
|
|
@click="handleCustomMode"
|
|
>
|
|
<template v-if="!isCustomMode">
|
|
<AInputNumber
|
|
v-model:value="customAmount"
|
|
:placeholder="t('page.carddata.Customization')"
|
|
:min="1"
|
|
:max="999"
|
|
class="w-full"
|
|
@change="handleCustomAmount"
|
|
@click.stop
|
|
@blur="handleBlur"
|
|
/>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 支付按钮 -->
|
|
<div class="payment-section mt-8 bg-white p-4 rounded-lg border border-gray-100">
|
|
<AButton
|
|
type="primary"
|
|
size="large"
|
|
block
|
|
:disabled="!paymentAmount || paymentAmount <= 0"
|
|
@click="handleRecharge"
|
|
>
|
|
<span style="color: var(--text-color, var(--ant-text-color))"> ¥{{ paymentAmount.toFixed(2) }} {{ t('page.carddata.pay') }} </span>
|
|
</AButton>
|
|
</div>
|
|
|
|
<!-- 订单确认弹窗 -->
|
|
<OrderConfirmModal
|
|
v-model:visible="showOrderModal"
|
|
:order-info="currentOrderInfo"
|
|
@confirm="handlePaymentConfirm"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.recharge-option {
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 8px;
|
|
padding: 16px;
|
|
text-align: center;
|
|
transition: all 0.3s;
|
|
height: 76px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
}
|
|
|
|
.recharge-option.selected,
|
|
.special-option.selected {
|
|
border-color: #1890ff;
|
|
background: rgba(63, 97, 207, 0.1);
|
|
}
|
|
|
|
.special-option {
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 8px;
|
|
padding: 0;
|
|
text-align: center;
|
|
display: flex;
|
|
align-items: stretch;
|
|
gap: 0;
|
|
transition: all 0.3s;
|
|
height: 76px;
|
|
}
|
|
|
|
.special-option :deep(.ant-input-number) {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 8px;
|
|
border: none;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.special-option :deep(.ant-input-number-input-wrap) {
|
|
height: 100%;
|
|
width: 100%;
|
|
}
|
|
|
|
.special-option :deep(.ant-input-number-input) {
|
|
height: 100%;
|
|
width: 100%;
|
|
text-align: center;
|
|
padding: 0 16px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
&::placeholder {
|
|
text-align: center;
|
|
color: #999;
|
|
}
|
|
}
|
|
|
|
.special-option :deep(.ant-input-number:focus),
|
|
.special-option :deep(.ant-input-number-focused) {
|
|
box-shadow: none;
|
|
border: none;
|
|
}
|
|
|
|
.payment-section {
|
|
background-color: var(--text-color, var(--ant-text-color)); /* 使用主题变量 */
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
/* 除之前的后缀样式 */
|
|
:deep(.ant-input-suffix) {
|
|
display: none;
|
|
}
|
|
</style>
|