Files
----/前端源码/uni-app/components/PaymentModal.vue

314 lines
7.3 KiB
Vue
Raw Permalink 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.
<template>
<view v-if="visible" class="payment-modal" @click="handleClose">
<view class="payment-modal-content" @click.stop>
<!-- 关闭按钮 -->
<view class="payment-close-btn" @click="handleClose">
<text class="payment-close-icon">×</text>
</view>
<!-- 商品信息 -->
<view class="payment-product">
<view class="payment-product-icon">{{ productIcon }}</view>
<text class="payment-product-name">{{ productName }}</text>
<text class="payment-product-desc">{{ productDesc }}</text>
</view>
<!-- 价格 -->
<view class="payment-price">
<text class="payment-price-symbol">¥</text>
<text class="payment-price-amount">{{ amount }}</text>
</view>
<!-- 支付方式 -->
<view class="payment-method">
<view class="payment-method-item payment-method-active">
<view class="payment-method-left">
<text class="payment-method-icon">💳</text>
<text class="payment-method-label">微信支付</text>
</view>
<view class="payment-method-check"></view>
</view>
</view>
<!-- 支付按钮 -->
<view class="payment-submit-btn" :class="{ 'payment-submit-disabled': paying }" @click="handlePay">
<text class="payment-submit-text">{{ paying ? '支付中...' : '立即支付' }}</text>
</view>
<!-- 提示 -->
<view class="payment-tips">
<text class="payment-tips-text">支付即代表同意服务协议隐私政策</text>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { wxPay } from "@/utils/payment";
import { isWechatBrowser, payWithWechatJsapiH5 } from "@/utils/wechat-h5-jsapi-pay";
declare const uni: any;
interface Props {
visible: boolean;
productName: string; // 商品名称
productDesc?: string; // 商品描述
productIcon?: string; // 商品图标
amount: number; // 支付金额
businessType: string; // 业务类型
businessId: number; // 业务ID
}
const props = withDefaults(defineProps<Props>(), {
productDesc: '',
productIcon: '📦'
});
const emit = defineEmits<{
close: [];
success: [outTradeNo: string];
fail: [msg: string];
}>();
const paying = ref(false);
// 处理支付:微信 H5 内与财运月度详批一致走 JSAPI其它环境走 uni 支付封装
const handlePay = async () => {
if (paying.value) return;
paying.value = true;
try {
if (typeof window !== 'undefined' && isWechatBrowser()) {
const r = await payWithWechatJsapiH5({
description: props.productDesc || props.productName,
totalAmountYuan: props.amount,
businessType: props.businessType,
businessId: props.businessId,
});
if (r.redirected) {
return;
}
if (r.ok) {
emit('success', r.outTradeNo || '');
handleClose();
} else if (r.msg && r.msg !== 'not_wechat') {
emit('fail', r.msg || '支付失败');
}
return;
}
const result = await wxPay({
description: props.productName,
total_amount: props.amount,
business_type: props.businessType,
business_id: props.businessId
});
if (result.success) {
uni.showToast({ title: '支付成功', icon: 'success' });
emit('success', result.outTradeNo || '');
handleClose();
} else {
emit('fail', (result as any).msg || '支付失败');
}
} catch (error: any) {
console.error('支付失败:', error);
uni.showToast({ title: error.msg || '支付失败', icon: 'none' });
emit('fail', error.msg || '支付失败');
} finally {
paying.value = false;
}
};
// 关闭弹窗
const handleClose = () => {
if (paying.value) {
uni.showToast({ title: '支付进行中,请稍候', icon: 'none' });
return;
}
emit('close');
};
</script>
<style scoped>
.payment-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
display: flex;
align-items: flex-end;
justify-content: center;
z-index: 9999;
}
.payment-modal-content {
width: 100%;
background-color: #fff;
border-radius: 32rpx 32rpx 0 0;
padding: 48rpx 32rpx;
padding-bottom: calc(48rpx + env(safe-area-inset-bottom, 0px));
position: relative;
animation: slideUp 0.3s ease-out;
}
@keyframes slideUp {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
.payment-close-btn {
position: absolute;
top: 24rpx;
right: 24rpx;
width: 56rpx;
height: 56rpx;
display: flex;
align-items: center;
justify-content: center;
}
.payment-close-icon {
font-size: 48rpx;
color: #999;
line-height: 1;
}
/* 商品信息 */
.payment-product {
display: flex;
flex-direction: column;
align-items: center;
gap: 16rpx;
margin-bottom: 48rpx;
}
.payment-product-icon {
font-size: 80rpx;
margin-bottom: 8rpx;
}
.payment-product-name {
font-size: 32rpx;
font-weight: 700;
color: #2c2c2c;
}
.payment-product-desc {
font-size: 24rpx;
color: #999;
}
/* 价格 */
.payment-price {
text-align: center;
margin-bottom: 48rpx;
}
.payment-price-symbol {
font-size: 40rpx;
color: #8b2323;
font-weight: 700;
}
.payment-price-amount {
font-size: 72rpx;
color: #8b2323;
font-weight: 700;
}
/* 支付方式 */
.payment-method {
margin-bottom: 32rpx;
}
.payment-method-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx;
background-color: #f5f5f5;
border-radius: 16rpx;
border: 2rpx solid transparent;
transition: all 0.3s;
}
.payment-method-active {
background-color: rgba(139, 35, 35, 0.05);
border-color: #8b2323;
}
.payment-method-left {
display: flex;
align-items: center;
gap: 16rpx;
}
.payment-method-icon {
font-size: 32rpx;
}
.payment-method-label {
font-size: 28rpx;
color: #2c2c2c;
font-weight: 500;
}
.payment-method-check {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
background-color: #8b2323;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
}
/* 支付按钮 */
.payment-submit-btn {
width: 100%;
padding: 28rpx 0;
background-color: #8b2323;
border-radius: 16rpx;
display: flex;
justify-content: center;
margin-bottom: 24rpx;
transition: opacity 0.3s;
}
.payment-submit-btn:active {
opacity: 0.8;
}
.payment-submit-disabled {
opacity: 0.6;
}
.payment-submit-text {
font-size: 32rpx;
font-weight: 700;
color: #f2e6d8;
}
/* 提示 */
.payment-tips {
text-align: center;
}
.payment-tips-text {
font-size: 20rpx;
color: #999;
}
</style>