2
0
Files
fe.wfc.user/src/components/order-confirm/orderConfirmModal.vue
2025-03-11 14:43:53 +08:00

263 lines
5.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { defineProps, defineEmits, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { AlipayOutlined, WechatOutlined, WalletOutlined } from '@ant-design/icons-vue';
import { Modal } from 'ant-design-vue';
const { t } = useI18n();
interface Props {
visible: boolean;
orderInfo: {
orderId: string;
orderType: number; // 0: 购买套餐, 1: 余额充值
orderAmount: number;
};
enableBalancePay?: boolean;
userBalance?: number;
loading?: boolean;
}
const props = defineProps<Props>();
const emit = defineEmits(['update:visible', 'confirm', 'cancel']);
const orderTypeMap = {
0: t('page.order.packagePurchase'),
1: t('page.order.balanceRecharge')
} as const;
const isBalancePayDisabled = computed(() => {
// 如果余额未定义,禁用按钮
if (props.userBalance === undefined) return true;
// 如果余额为0禁用按钮
if (props.userBalance === 0) return true;
// 如果余额小于订单金额,禁用按钮
if (props.userBalance < props.orderInfo.orderAmount) return true;
// 如果正在加载,禁用按钮
return props.loading || false;
});
const handleConfirm = (paymentMethod: 'alipay' | 'wxpay' | 'balance') => {
if (paymentMethod === 'balance') {
Modal.confirm({
title: t('page.order.confirmPayment'),
content: t('page.order.balancePayConfirm'),
okText: t('page.order.confirm'),
cancelText: t('page.order.cancel'),
onOk: () => {
emit('confirm', paymentMethod);
}
});
} else {
emit('confirm', paymentMethod);
}
};
const handleCancel = () => {
if (props.loading) {
return;
}
emit('update:visible', false);
emit('cancel');
};
</script>
<template>
<a-modal
:visible="visible"
:title="t('page.order.confirmOrder')"
:footer="null"
@cancel="handleCancel"
width="460px"
:maskClosable="false"
:closable="!loading"
>
<a-spin :spinning="loading" tip="Processing payment...">
<div class="order-info">
<div class="info-item">
<span class="label">{{ t('page.order.orderType') }}</span>
<span class="value">{{ orderTypeMap[orderInfo.orderType] }}</span>
</div>
<div class="info-item">
<span class="label">{{ t('page.order.orderAmount') }}</span>
<span class="value highlight">¥{{ orderInfo.orderAmount.toFixed(2) }}</span>
</div>
<div class="info-item">
<span class="label">{{ t('page.order.orderId') }}</span>
<span class="value">{{ orderInfo.orderId }}</span>
</div>
</div>
<div class="payment-methods">
<h4>{{ t('page.order.selectPayment') }}</h4>
<div class="methods-container">
<div
v-if="orderInfo.orderType === 0"
class="method-item"
:class="{
disabled: isBalancePayDisabled,
}"
@click="!isBalancePayDisabled && handleConfirm('balance')"
>
<div class="debug-info" style="display: none;">
Enable balance pay: {{ enableBalancePay }}
</div>
<WalletOutlined class="payment-icon balance-icon" />
<span>{{ t('page.order.balancePay') }}</span>
<div class="balance-info" v-if="userBalance !== undefined">
{{ t('page.order.availableBalance') }}: ¥{{ userBalance.toFixed(2) }}
<template v-if="userBalance < orderInfo.orderAmount">
<br>
<span class="balance-insufficient">{{ t('page.order.insufficientBalance') }}</span>
</template>
</div>
</div>
<div
class="method-item"
:class="{ disabled: loading }"
@click="!loading && handleConfirm('alipay')"
>
<AlipayOutlined class="payment-icon alipay-icon" />
<span>{{ t('page.order.alipay') }}</span>
</div>
<div
class="method-item"
:class="{ disabled: loading }"
@click="!loading && handleConfirm('wxpay')"
>
<WechatOutlined class="payment-icon wxpay-icon" />
<span>{{ t('page.order.wxpay') }}</span>
</div>
</div>
</div>
</a-spin>
</a-modal>
</template>
<style scoped>
.order-info {
padding: 20px;
background: #f8f8f8;
border-radius: 8px;
margin-bottom: 24px;
}
.info-item {
display: flex;
margin-bottom: 16px;
line-height: 24px;
font-size: 14px;
}
.info-item:last-child {
margin-bottom: 0;
}
.label {
width: 84px;
color: #666;
}
.value {
flex: 1;
color: #333;
}
.value.highlight {
color: #ff4d4f;
font-size: 16px;
font-weight: 500;
}
.payment-methods {
padding: 0 4px;
}
.payment-methods h4 {
margin-bottom: 16px;
color: #333;
font-size: 14px;
font-weight: normal;
}
.methods-container {
display: flex;
gap: 12px;
}
.method-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 16px;
border: 1px solid #e8e8e8;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
}
.method-item:hover {
border-color: #1890ff;
background: #f0f5ff;
}
.payment-icon {
font-size: 24px;
margin-bottom: 8px;
}
.alipay-icon {
color: #1677ff;
}
.wxpay-icon {
color: #07c160;
}
.method-item.disabled {
opacity: 0.5;
cursor: not-allowed;
background: #f5f5f5;
}
.balance-icon {
color: #52c41a;
}
.balance-info {
font-size: 12px;
color: #666;
margin-top: 4px;
}
.balance-insufficient {
color: #ff4d4f;
font-size: 12px;
display: block;
text-align: center;
margin-top: 4px;
}
:deep(.ant-spin-container) {
position: relative;
}
:deep(.ant-spin) {
max-height: none;
}
:deep(.ant-spin-spinning) {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
background: rgba(255, 255, 255, 0.6);
display: flex;
align-items: center;
justify-content: center;
}
</style>