2
0
Files
fe.wfc.user/src/views/recharge/balancerecharge/index.vue
2025-02-26 15:22:33 +08:00

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>