ef5fda73 by 张猛

个人会员缴费支付

1 parent 564e3119
1 <template> 1 <template>
2 <view class="container"> 2 <view class="container">
3 <view class="content"> 3 <view class="content">
4 <view class="card"> 4 <view class="card">
5 <view class="yearRow"> 5 <view class="yearRow">
6 <view class="label">缴费年限</view> 6 <view class="label">缴费年限</view>
7 <view class="control"> 7 <view class="control">
8 <image class="icon" @click="minusYear" :src="config.baseUrl_api + '/fs/static/dd_02.png'" mode="widthFix" 8 <image v-if="form.payYear > 1" :src="config.baseUrl_api + '/fs/static/dd_02.png'" class="icon"
9 v-if="form.payYear > 1"></image> 9 mode="widthFix"
10 <image class="icon" :src="config.baseUrl_api + '/fs/static/dd_02_g.png'" mode="widthFix" v-else></image> 10 @click="minusYear"></image>
11 <text class="num">{{ form.payYear }}</text> 11 <image v-else :src="config.baseUrl_api + '/fs/static/dd_02_g.png'" class="icon" mode="widthFix"></image>
12 <image class="icon" :src="config.baseUrl_api + '/fs/static/btn_03.png'" mode="widthFix" @click="plusYear" 12 <text class="num">{{ form.payYear }}</text>
13 v-if="form.payYear < 5"></image> 13 <image v-if="form.payYear < 5" :src="config.baseUrl_api + '/fs/static/btn_03.png'" class="icon"
14 <image class="icon" :src="config.baseUrl_api + '/fs/static/btn_03_g.png'" mode="widthFix" v-else></image> 14 mode="widthFix"
15 </view> 15 @click="plusYear"></image>
16 </view> 16 <image v-else :src="config.baseUrl_api + '/fs/static/btn_03_g.png'" class="icon" mode="widthFix"></image>
17 </view> 17 </view>
18 18 </view>
19 <view class="card "> 19 </view>
20 <view class="row "> 20
21 <text class="label">费用合计</text> 21 <view class="card ">
22 <text class="value red">{{ form.payYear * memberFee }}</text> 22 <view class="row ">
23 </view> 23 <text class="label">费用合计</text>
24 24 <text class="value red">{{ form.payYear * memberFee }}</text>
25 </view> 25 </view>
26 26
27 <view class="payRow "> 27 </view>
28 <radio-group @change="onPayTypeChange"> 28
29 <label class="radioItem"> 29 <view class="payRow ">
30 <radio value="1" :checked="payType === '1'" class="custom-radio" /> 30 <radio-group @change="onPayTypeChange">
31 <view class="payInfo"> 31 <label class="radioItem">
32 <image class="icon" :src="config.baseUrl_api + '/fs/static/min.png'" mode="widthFix"></image> 32 <radio :checked="payType === '1'" class="custom-radio" value="1"/>
33 <text>民生付</text> 33 <view class="payInfo">
34 </view> 34 <image :src="config.baseUrl_api + '/fs/static/min.png'" class="icon" mode="widthFix"></image>
35 </label> 35 <text>民生付</text>
36 </radio-group> 36 </view>
37 </view> 37 </label>
38 38 </radio-group>
39 <view class="totalRow "> 39 </view>
40 <text class="label">支付费用合计</text> 40
41 <text class="value redBig">{{ memberTotalFee }}</text> 41 <view class="totalRow ">
42 </view> 42 <text class="label">支付费用合计</text>
43 43 <text class="value redBig">{{ memberTotalFee }}</text>
44 </view> 44 </view>
45 45
46 <view class="bottomBtn"> 46 </view>
47 <button class="payBtn" @click="handelPay" :loading="isPaying">立即支付 ¥{{ memberTotalFee }}</button> 47
48 </view> 48 <view class="bottomBtn">
49 49 <button :loading="isPaying" class="payBtn" @click="handelPay">立即支付 ¥{{ memberTotalFee }}</button>
50 </view> 50 </view>
51
52 </view>
51 </template> 53 </template>
52 54
53 <script setup> 55 <script setup>
54 import { 56 import {
55 ref, 57 ref,
56 computed, 58 computed,
57 onMounted 59 onMounted
58 } from 'vue' 60 } from 'vue'
59 import { 61 import {
60 onLoad 62 onLoad
61 } from '@dcloudio/uni-app'; 63 } from '@dcloudio/uni-app';
62 import to from 'await-to-js' 64 import to from 'await-to-js'
63 import * as api from '@/common/api.js' 65 import * as api from '@/common/api.js'
64 import { 66 import {
65 minShengPay 67 minShengPay
66 } from '@/common/pay.js' 68 } from '@/common/pay.js'
67 import config from '@/config.js' 69 import config from '@/config.js'
68 const form = ref({ 70
69 payYear: 1 71 const form = ref({
70 }) 72 payYear: 1
71 73 })
72 // 支付方式 74
73 const payType = ref('1') 75 // 支付方式
74 const isPaying = ref(false) 76 const payType = ref('1')
75 77 const isPaying = ref(false)
76 // 费用与优惠 78
77 const memberFee = ref(0) 79 // 费用与优惠
78 const memberTotalFee = computed(() => { 80 const memberFee = ref(0)
79 return memberFee.value * form.value.payYear 81 const memberTotalFee = computed(() => {
80 82 return memberFee.value * form.value.payYear
81 }) 83
82 onLoad((options) => { 84 })
83 if (options.baseFormData) { 85 onLoad((options) => {
84 const data = JSON.parse(decodeURIComponent(options.baseFormData)) 86 if (options.baseFormData) {
85 form.value = { 87 const data = JSON.parse(decodeURIComponent(options.baseFormData))
86 ...data, 88 form.value = {
87 payYear: 1 // 年限默认1 89 ...data,
88 } 90 payYear: 1 // 年限默认1
89 } 91 }
90 // 初始化接口 92 }
91 getMyMemberCertUnitFeeApi() 93 // 初始化接口
92 }) 94 getMyMemberCertUnitFeeApi()
93 95 })
94 96
95 97
96 // 减年限 98 // 减年限
97 const minusYear = () => { 99 const minusYear = () => {
98 if (form.value.payYear > 1) { 100 if (form.value.payYear > 1) {
99 form.value.payYear-- 101 form.value.payYear--
100 } 102 }
101 } 103 }
102 104
103 // 加年限(最大 5 年) 105 // 加年限(最大 5 年)
104 const plusYear = () => { 106 const plusYear = () => {
105 if (form.value.payYear < 5) { 107 if (form.value.payYear < 5) {
106 form.value.payYear++ 108 form.value.payYear++
107 } 109 }
108 } 110 }
109 111
110 // 支付方式切换 112 // 支付方式切换
111 const onPayTypeChange = (e) => { 113 const onPayTypeChange = (e) => {
112 payType.value = e.detail.value 114 payType.value = e.detail.value
113 } 115 }
114 116
115 const handelPay = async () => { 117 const handelPay = async () => {
116 if (memberTotalFee.value <= 0) { 118 if (memberTotalFee.value <= 0) {
117 uni.showToast({ 119 uni.showToast({
118 title: '支付金额异常', 120 title: '支付金额异常',
119 icon: 'none' 121 icon: 'none'
120 }) 122 })
121 return 123 return
122 } 124 }
123 125
124 // 显示 loading 126 // 显示 loading
125 uni.showLoading({ 127 uni.showLoading({
126 title: '创建订单...', 128 title: '创建订单...',
127 mask: true 129 mask: true
128 }) 130 })
129 isPaying.value = true 131 isPaying.value = true
130 132 form.value.validityDate = undefined
131 // 拼接完整参数 133 // 拼接完整参数
132 const postData = { 134 const postData = {
133 ...form.value, 135 ...form.value,
134 payYear: form.value.payYear, 136 payYear: form.value.payYear,
135 payType: payType.value, 137 payType: payType.value,
136 totalFee: memberTotalFee.value 138 totalFee: memberTotalFee.value,
137 } 139 }
138 140
139 // 创建订单 141 // 创建订单
140 const [orderErr, orderRes] = await to(api.insertSinglePay(postData)) 142 const [orderErr, orderRes] = await to(api.insertSinglePay(postData))
141 uni.hideLoading() 143 uni.hideLoading()
142 144
143 if (orderErr) { 145 if (orderErr) {
144 isPaying.value = false 146 isPaying.value = false
145 // uni.showToast({ 147 // uni.showToast({
146 // title: '创建订单失败', 148 // title: '创建订单失败',
147 // icon: 'none' 149 // icon: 'none'
148 // }) 150 // })
149 return 151 return
150 } 152 }
151 153
152 if (!orderRes.data?.orderId) { 154 if (!orderRes.data?.orderId) {
153 isPaying.value = false 155 isPaying.value = false
154 uni.showToast({ 156 uni.showToast({
155 title: '订单创建异常', 157 title: '订单创建异常',
156 icon: 'none' 158 icon: 'none'
157 }) 159 })
158 return 160 return
159 } 161 }
160 162
161 // 调起支付 163 // 调起支付
162 const [payErr] = await to(minShengPay(orderRes.data.orderId, orderRes.data.payResult.encryptedData)) 164 const [payErr] = await to(minShengPay(orderRes.data.orderId, orderRes.data.payResult.encryptedData))
163 165
164 isPaying.value = false 166 isPaying.value = false
165 167
166 // 支付失败不跳转 168 // 支付失败不跳转
167 if (payErr) { 169 if (payErr) {
168 return 170 return
169 } 171 }
170 172
171 // 支付成功,跳转页面 173 // 支付成功,跳转页面
172 uni.redirectTo({ 174 uni.redirectTo({
173 url: `/personal/sucPay?orderId=${orderRes.data.orderId}` 175 url: `/personal/sucPay?orderId=${orderRes.data.orderId}`
174 }) 176 })
175 } 177 }
176 178
177 179
178 180 // 获取会员费
179 // 获取会员费 181 async function getMyMemberCertUnitFeeApi() {
180 async function getMyMemberCertUnitFeeApi() { 182 const res = await api.getZtxFeeConfig()
181 const res = await api.getZtxFeeConfig() 183 memberFee.value = Number(res.data.personMemberFee || 1500)
182 memberFee.value = Number(res.data.personMemberFee || 1500) 184 }
183 }
184 </script> 185 </script>
185 186
186 <style scoped> 187 <style scoped>
187 .container {
188 min-height: 100vh;
189 background-color: #f7f7f7;
190 }
191
192 .content {
193 padding: 20rpx 20rpx 120rpx;
194 }
195
196 .card {
197 background: #fff;
198 border-radius: 8rpx;
199 padding: 25rpx 20rpx;
200 margin-bottom: 20rpx;
201 }
202
203 .yearRow {
204 display: flex;
205 align-items: center;
206 justify-content: space-between;
207 margin-bottom: 20rpx;
208 }
209
210 .yearRow .label {
211 font-size: 28rpx;
212 color: #333;
213 }
214
215 .yearRow .control {
216 display: flex;
217 align-items: center;
218 }
219
220 .control image {
221 width: 50rpx;
222 height: 50rpx;
223 }
224
225 .yearRow .num {
226 font-size: 28rpx;
227 color: #333;
228 min-width: 80rpx;
229 text-align: center;
230 margin: 0 10rpx;
231 }
232
233 .row {
234 display: flex;
235 justify-content: space-between;
236 align-items: center;
237 }
238
239 .row .label {
240 font-size: 28rpx;
241 color: #333;
242 }
243
244 .row .value {
245 font-size: 30rpx;
246 color: #C4121B;
247 font-weight: 500;
248 }
249
250 .hintRow {
251 display: flex;
252 align-items: flex-start;
253 font-size: 24rpx;
254 line-height: 1.4;
255 }
256
257 .hintRow .hintText {
258 color: #FF8124;
259 flex: 1;
260 margin-top: 10rpx;
261 }
262
263 .deductRow {
264 background: #fff;
265 padding: 20rpx 20rpx;
266 display: flex;
267 justify-content: space-between;
268 align-items: center;
269 margin-bottom: 10rpx;
270 border-radius: 8rpx;
271 }
272
273 .deductRow .label {
274 font-size: 28rpx;
275 color: #333;
276 }
277
278 .deductRow .value {
279 font-size: 30rpx;
280 color: #C4121B;
281 }
282
283 .payRow {
284 background: #fff;
285 border-radius: 8rpx;
286 padding: 20rpx 20rpx;
287 margin-bottom: 20rpx;
288 }
289
290 .radioItem {
291 display: flex;
292 align-items: center;
293 }
294
295 .payInfo {
296 display: flex;
297 align-items: center;
298 margin-left: 15rpx;
299 }
300
301 .payInfo .icon {
302 width: 40rpx;
303 height: 40rpx;
304 margin-right: 10rpx;
305 }
306
307 .payInfo text {
308 font-size: 28rpx;
309 color: #333;
310 }
311
312 .totalRow {
313 background: #fff;
314 border-radius: 8rpx;
315 padding: 20rpx 20rpx;
316 display: flex;
317 justify-content: space-between;
318 align-items: center;
319 margin-top: 10rpx;
320 }
321
322 .totalRow .label {
323 font-size: 28rpx;
324 color: #333;
325 }
326
327 .redBig {
328 font-size: 32rpx;
329 color: #C4121B;
330 font-weight: bold;
331 }
332
333 .bottomBtn {
334 position: fixed;
335 bottom: 0;
336 left: 0;
337 right: 0;
338 padding: 20rpx 20rpx;
339 background: #fff;
340 border-top: 1rpx solid #eee;
341 }
342
343 .payBtn {
344 width: 100%;
345 height: 88rpx;
346 line-height: 88rpx;
347 background-color: #C4121B;
348 color: #fff;
349 border-radius: 8rpx;
350 font-size: 32rpx;
351 text-align: center;
352 border: none;
353 }
354
355 .payBtn[disabled] {
356 background-color: #ccc;
357 color: #999;
358 }
359
360 .red {
361 color: #C4121B;
362 }
363
364 .icon {
365 width: 30px;
366 }
367
368 ::v-deep .custom-radio .wx-radio-input {
369 width: 30rpx;
370 height: 30rpx;
371 border-radius: 50%;
372 border: 2rpx solid #ccc;
373 }
374
375 ::v-deep .custom-radio .wx-radio-input.wx-radio-input-checked {
376 border-color: #C4121B !important;
377 background: #C4121B !important;
378 }
379 </style>
...\ No newline at end of file ...\ No newline at end of file
188 .container {
189 min-height: 100vh;
190 background-color: #f7f7f7;
191 }
192
193 .content {
194 padding: 20rpx 20rpx 120rpx;
195 }
196
197 .card {
198 background: #fff;
199 border-radius: 8rpx;
200 padding: 25rpx 20rpx;
201 margin-bottom: 20rpx;
202 }
203
204 .yearRow {
205 display: flex;
206 align-items: center;
207 justify-content: space-between;
208 margin-bottom: 20rpx;
209 }
210
211 .yearRow .label {
212 font-size: 28rpx;
213 color: #333;
214 }
215
216 .yearRow .control {
217 display: flex;
218 align-items: center;
219 }
220
221 .control image {
222 width: 50rpx;
223 height: 50rpx;
224 }
225
226 .yearRow .num {
227 font-size: 28rpx;
228 color: #333;
229 min-width: 80rpx;
230 text-align: center;
231 margin: 0 10rpx;
232 }
233
234 .row {
235 display: flex;
236 justify-content: space-between;
237 align-items: center;
238 }
239
240 .row .label {
241 font-size: 28rpx;
242 color: #333;
243 }
244
245 .row .value {
246 font-size: 30rpx;
247 color: #C4121B;
248 font-weight: 500;
249 }
250
251 .hintRow {
252 display: flex;
253 align-items: flex-start;
254 font-size: 24rpx;
255 line-height: 1.4;
256 }
257
258 .hintRow .hintText {
259 color: #FF8124;
260 flex: 1;
261 margin-top: 10rpx;
262 }
263
264 .deductRow {
265 background: #fff;
266 padding: 20rpx 20rpx;
267 display: flex;
268 justify-content: space-between;
269 align-items: center;
270 margin-bottom: 10rpx;
271 border-radius: 8rpx;
272 }
273
274 .deductRow .label {
275 font-size: 28rpx;
276 color: #333;
277 }
278
279 .deductRow .value {
280 font-size: 30rpx;
281 color: #C4121B;
282 }
283
284 .payRow {
285 background: #fff;
286 border-radius: 8rpx;
287 padding: 20rpx 20rpx;
288 margin-bottom: 20rpx;
289 }
290
291 .radioItem {
292 display: flex;
293 align-items: center;
294 }
295
296 .payInfo {
297 display: flex;
298 align-items: center;
299 margin-left: 15rpx;
300 }
301
302 .payInfo .icon {
303 width: 40rpx;
304 height: 40rpx;
305 margin-right: 10rpx;
306 }
307
308 .payInfo text {
309 font-size: 28rpx;
310 color: #333;
311 }
312
313 .totalRow {
314 background: #fff;
315 border-radius: 8rpx;
316 padding: 20rpx 20rpx;
317 display: flex;
318 justify-content: space-between;
319 align-items: center;
320 margin-top: 10rpx;
321 }
322
323 .totalRow .label {
324 font-size: 28rpx;
325 color: #333;
326 }
327
328 .redBig {
329 font-size: 32rpx;
330 color: #C4121B;
331 font-weight: bold;
332 }
333
334 .bottomBtn {
335 position: fixed;
336 bottom: 0;
337 left: 0;
338 right: 0;
339 padding: 20rpx 20rpx;
340 background: #fff;
341 border-top: 1rpx solid #eee;
342 }
343
344 .payBtn {
345 width: 100%;
346 height: 88rpx;
347 line-height: 88rpx;
348 background-color: #C4121B;
349 color: #fff;
350 border-radius: 8rpx;
351 font-size: 32rpx;
352 text-align: center;
353 border: none;
354 }
355
356 .payBtn[disabled] {
357 background-color: #ccc;
358 color: #999;
359 }
360
361 .red {
362 color: #C4121B;
363 }
364
365 .icon {
366 width: 30px;
367 }
368
369 ::v-deep .custom-radio .wx-radio-input {
370 width: 30rpx;
371 height: 30rpx;
372 border-radius: 50%;
373 border: 2rpx solid #ccc;
374 }
375
376 ::v-deep .custom-radio .wx-radio-input.wx-radio-input-checked {
377 border-color: #C4121B !important;
378 background: #C4121B !important;
379 }
380 </style>
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!