goPay_per.vue 6.85 KB
<template>
	<view class="container">
		<view class="content">
			<view class="card">
				<view class="yearRow">
					<view class="label">缴费年限</view>
					<view class="control">
						<image class="icon" @click="minusYear" src="/static/dd_02.png" mode="widthFix"
							v-if="form.payYear > 1"></image>
						<image class="icon" src="/static/dd_02_g.png" mode="widthFix" v-else></image>
						<text class="num">{{ form.payYear }}</text>
						<image class="icon" src="/static/btn_03.png" mode="widthFix" @click="plusYear"
							v-if="form.payYear < 5"></image>
						<image class="icon" src="/static/btn_03_g.png" mode="widthFix" v-else></image>
					</view>
				</view>
			</view>

			<view class="card ">
				<view class="row ">
					<text class="label">费用合计</text>
					<text class="value red">{{ form.payYear * memberFee }}</text>
				</view>

			</view>

			<view class="payRow ">
				<radio-group @change="onPayTypeChange">
					<label class="radioItem">
						<radio value="1" :checked="payType === '1'" class="custom-radio" />
						<view class="payInfo">
							<image class="icon" src="/static/min.png" mode="widthFix"></image>
							<text>民生付</text>
						</view>
					</label>
				</radio-group>
			</view>

			<view class="totalRow ">
				<text class="label">支付费用合计</text>
				<text class="value redBig">{{ memberTotalFee }}</text>
			</view>

		</view>

		<view class="bottomBtn">
			<button class="payBtn" @click="handelPay" :loading="isPaying">立即支付 ¥{{ memberTotalFee }}</button>
		</view>

	</view>
</template>

<script setup>
	import {
		ref,
		computed,
		onMounted
	} from 'vue'
	import {
		onLoad
	} from '@dcloudio/uni-app';
	import to from 'await-to-js'
	import * as api from '@/common/api.js'

	const form = ref({
		payYear: 1
	})

	// 支付方式
	const payType = ref('1')
	const isPaying = ref(false)

	// 费用与优惠
	const memberFee = ref(0)
	const memberTotalFee = computed(() => {
		return memberFee.value * form.value.payYear

	})
	onLoad((options) => {
		if (options.baseFormData) {
			const data = JSON.parse(decodeURIComponent(options.baseFormData))
			form.value = {
				...data,
				payYear: 1 // 年限默认1
			}
		}
		// 初始化接口
		getMyMemberCertUnitFeeApi()
	})



	// 减年限
	const minusYear = () => {
		if (form.value.payYear > 1) {
			form.value.payYear--
		}
	}

	// 加年限(最大 5 年)
	const plusYear = () => {
		if (form.value.payYear < 5) {
			form.value.payYear++
		}
	}

	// 支付方式切换
	const onPayTypeChange = (e) => {
		payType.value = e.detail.value
	}

	const handelPay = async () => {
		if (memberTotalFee.value <= 0) {
			uni.showToast({
				title: '支付金额异常',
				icon: 'none'
			})
			return
		}

		// 显示 loading
		uni.showLoading({
			title: '支付中...',
			mask: true
		})
		isPaying.value = true

		// 拼接完整参数
		const postData = {
			...form.value,
			payYear: form.value.payYear,
			payType: payType.value,
			totalFee: memberTotalFee.value
		}

		// 创建订单
		const [orderErr, orderRes] = await to(api.insertSinglePay(postData))
		if (orderErr) {
			uni.hideLoading()
			isPaying.value = false
			// uni.showToast({
			// 	title: '创建订单失败',
			// 	icon: 'none'
			// })
			return
		}

		if (!orderRes.data?.orderId) {
			uni.hideLoading()
			isPaying.value = false
			uni.showToast({
				title: '订单创建异常',
				icon: 'none'
			})
			return
		}

		// 等待支付回调
		await to(api.pcallBack2(orderRes.data.orderId))
		uni.hideLoading()
		isPaying.value = false

		// 支付成功,跳转页面
		uni.redirectTo({
			url: `/personal/sucPay?orderId=${orderRes.data.orderId}`
		})
	}



	// 获取会员费
	async function getMyMemberCertUnitFeeApi() {
		const res = await api.getZtxFeeConfig()
		memberFee.value = Number(res.data.personMemberFee || 1500)
	}
</script>

<style scoped>
	.container {
		min-height: 100vh;
		background-color: #f7f7f7;
	}

	.content {
		padding: 20rpx 20rpx 120rpx;
	}

	.card {
		background: #fff;
		border-radius: 8rpx;
		padding: 25rpx 20rpx;
		margin-bottom: 20rpx;
	}

	.yearRow {
		display: flex;
		align-items: center;
		justify-content: space-between;
		margin-bottom: 20rpx;
	}

	.yearRow .label {
		font-size: 28rpx;
		color: #333;
	}

	.yearRow .control {
		display: flex;
		align-items: center;
	}

	.control image {
		width: 50rpx;
		height: 50rpx;
	}

	.yearRow .num {
		font-size: 28rpx;
		color: #333;
		min-width: 80rpx;
		text-align: center;
		margin: 0 10rpx;
	}

	.row {
		display: flex;
		justify-content: space-between;
		align-items: center;
	}

	.row .label {
		font-size: 28rpx;
		color: #333;
	}

	.row .value {
		font-size: 30rpx;
		color: #C4121B;
		font-weight: 500;
	}

	.hintRow {
		display: flex;
		align-items: flex-start;
		font-size: 24rpx;
		line-height: 1.4;
	}

	.hintRow .hintText {
		color: #FF8124;
		flex: 1;
		margin-top: 10rpx;
	}

	.deductRow {
		background: #fff;
		padding: 20rpx 20rpx;
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-bottom: 10rpx;
		border-radius: 8rpx;
	}

	.deductRow .label {
		font-size: 28rpx;
		color: #333;
	}

	.deductRow .value {
		font-size: 30rpx;
		color: #C4121B;
	}

	.payRow {
		background: #fff;
		border-radius: 8rpx;
		padding: 20rpx 20rpx;
		margin-bottom: 20rpx;
	}

	.radioItem {
		display: flex;
		align-items: center;
	}

	.payInfo {
		display: flex;
		align-items: center;
		margin-left: 15rpx;
	}

	.payInfo .icon {
		width: 40rpx;
		height: 40rpx;
		margin-right: 10rpx;
	}

	.payInfo text {
		font-size: 28rpx;
		color: #333;
	}

	.totalRow {
		background: #fff;
		border-radius: 8rpx;
		padding: 20rpx 20rpx;
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-top: 10rpx;
	}

	.totalRow .label {
		font-size: 28rpx;
		color: #333;
	}

	.redBig {
		font-size: 32rpx;
		color: #C4121B;
		font-weight: bold;
	}

	.bottomBtn {
		position: fixed;
		bottom: 0;
		left: 0;
		right: 0;
		padding: 20rpx 20rpx;
		background: #fff;
		border-top: 1rpx solid #eee;
	}

	.payBtn {
		width: 100%;
		height: 88rpx;
		line-height: 88rpx;
		background-color: #C4121B;
		color: #fff;
		border-radius: 8rpx;
		font-size: 32rpx;
		text-align: center;
		border: none;
	}

	.payBtn[disabled] {
		background-color: #ccc;
		color: #999;
	}

	.red {
		color: #C4121B;
	}

	.icon {
		width: 30px;
	}

	::v-deep .custom-radio .wx-radio-input {
		width: 30rpx;
		height: 30rpx;
		border-radius: 50%;
		border: 2rpx solid #ccc;
	}

	::v-deep .custom-radio .wx-radio-input.wx-radio-input-checked {
		border-color: #C4121B !important;
		background: #C4121B !important;
	}
</style>