upload project source code

This commit is contained in:
2026-04-30 18:49:43 +08:00
commit 9b394ba682
2277 changed files with 660945 additions and 0 deletions

View File

@@ -0,0 +1,313 @@
<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>