@uxda/appkit 4.3.0 → 4.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,28 +1,58 @@
1
1
  <template>
2
2
  <view class="view recharge-view2">
3
3
  <view class="flex-grow">
4
- <rights-picker :items="amounts" :selected="state.selected" @change="onAmountSelect" />
4
+ <rights-picker
5
+ :items="amounts"
6
+ :selected="state.selected"
7
+ @change="onAmountSelect"
8
+ />
5
9
  <div class="bean-buy" v-if="amounts[state.selected]">
6
10
  <div class="left">
7
11
  <div class="title">使用云豆支付</div>
8
- <div class="amount" v-if="!selectBean">余额 {{ formatAmount(balance || 0) }}</div>
9
- <div class="amount" v-else>扣减后余额 {{ formatAmount(balance - amounts[state.selected].paymentAmount) }}</div>
12
+ <div class="amount" v-if="!selectBean || isCombinedPayment">
13
+ 余额 {{ formatAmount(balance || 0) }}
14
+ </div>
15
+ <div class="amount" v-else>
16
+ 扣减后余额
17
+ {{ formatAmount(balance - amounts[state.selected].paymentAmount) }}
18
+ </div>
10
19
  </div>
11
- <div class="right" v-if="balance >= amounts[state.selected].paymentAmount" @click="selectBean = !selectBean">
12
- <div class="amount">-{{ formatAmount(amounts[state.selected].paymentAmount || 0) }}</div>
13
- <img class="icon"
14
- :src="selectBean ? 'https://cdn.ddjf.com/static/images/appkit/select.svg' : 'https://cdn.ddjf.com/static/images/appkit/not-select.svg'" />
20
+ <div class="right" @click="selectBean = !selectBean">
21
+ <div class="amount">
22
+ -{{ formatAmount(amounts[state.selected].paymentAmount || 0) }}
23
+ </div>
24
+ <img
25
+ class="icon"
26
+ :src="
27
+ selectBean
28
+ ? 'https://cdn.ddjf.com/static/images/appkit/select.svg'
29
+ : 'https://cdn.ddjf.com/static/images/appkit/not-select.svg'
30
+ "
31
+ />
32
+ </div>
33
+
34
+ <div class="balance-warning" v-if="isCombinedPayment">
35
+ 云豆余额不足,还需额外支付{{ formatAmount(extraPaymentAmount) }}元
15
36
  </div>
16
37
  </div>
17
38
 
39
+ <div class="balance-warning-tip" v-if="isCombinedPayment">
40
+ 请在支付完成前确保元豆余额不被消耗,否则本次权益可能购买失败
41
+ </div>
18
42
 
19
43
  <slot name="banner"></slot>
20
44
  </view>
21
45
 
22
46
  <view class="amount-footer">
23
- <view class="agreement" v-if="!selectBean">
24
- <nut-checkbox v-model="state.agreed">我已阅读并同意<a v-track-click class="link inline"
25
- @click="onAgreementLinkClick">《大道云平台云豆充值服务协议》</a></nut-checkbox>
47
+ <view class="agreement" v-if="!selectBean || isCombinedPayment">
48
+ <nut-checkbox v-model="state.agreed"
49
+ >我已阅读并同意<a
50
+ v-track-click
51
+ class="link inline"
52
+ @click="onAgreementLinkClick"
53
+ >《大道云平台云豆充值服务协议》</a
54
+ ></nut-checkbox
55
+ >
26
56
  </view>
27
57
  <div class="buy-amount">
28
58
  <div class="left">
@@ -31,29 +61,53 @@
31
61
  <i>¥</i>{{ formatAmount(currentAmount) }}
32
62
  </span>
33
63
  </div>
34
- <nut-button block shape="square" :loading="state.buttonLoading" v-track-click @click="onPayClick"
35
- class="recharge-button">购买</nut-button>
64
+ <nut-button
65
+ block
66
+ shape="square"
67
+ :loading="state.buttonLoading"
68
+ v-track-click
69
+ @click="onPayClick"
70
+ class="recharge-button"
71
+ >购买</nut-button
72
+ >
36
73
  </div>
37
74
  </view>
38
- <nut-dialog title="确认购买" custom-class="trade-dialog" v-model:visible="showDialog" @cancel="showDialog = !showDialog"
39
- @ok="beanPay">
75
+ <nut-dialog
76
+ title="确认购买"
77
+ custom-class="trade-dialog"
78
+ v-model:visible="showDialog"
79
+ @cancel="showDialog = !showDialog"
80
+ @ok="beanPay"
81
+ >
40
82
  <template v-if="amounts[state.selected]">
41
- <div class="item">云豆扣减:{{ formatAmount(amounts[state.selected].paymentAmount || 0) }}</div>
42
- <div class="item">权益增加:{{ formatAmount(amounts[state.selected].priceRightNum || 0) }}笔</div>
43
- <div class="item">扣减后云豆余额:{{ formatAmount(balance - amounts[state.selected].paymentAmount) }}</div>
83
+ <div class="item">
84
+ 云豆扣减:{{
85
+ formatAmount(amounts[state.selected].paymentAmount || 0)
86
+ }}
87
+ </div>
88
+ <div class="item">
89
+ 权益增加:{{
90
+ formatAmount(amounts[state.selected].priceRightNum || 0)
91
+ }}笔
92
+ </div>
93
+ <div class="item">
94
+ 扣减后云豆余额:{{
95
+ formatAmount(balance - amounts[state.selected].paymentAmount)
96
+ }}
97
+ </div>
44
98
  </template>
45
99
  </nut-dialog>
46
100
  </view>
47
101
  </template>
48
102
 
49
103
  <script lang="ts" setup>
50
- import { computed, onMounted, reactive, ref } from 'vue'
51
- import RightsPicker, { Amount } from './RightsPicker.vue'
52
- import { endpoints, useHttp } from '../api'
53
- import { requestBrandWCPayByBean, requestPaymentByBean } from '../services'
54
- import Taro, { showToast, useRouter } from '@tarojs/taro'
55
- import { useAmount } from '../../shared/composables/useAmount'
56
- import { isWechat } from '../../shared/composables/useDeviceEnv'
104
+ import { computed, onMounted, reactive, ref } from "vue";
105
+ import RightsPicker, { Amount } from "./RightsPicker.vue";
106
+ import { endpoints, useHttp } from "../api";
107
+ import { requestBrandWCPayByBean, requestPaymentByBean } from "../services";
108
+ import Taro, { showToast, useRouter } from "@tarojs/taro";
109
+ import { useAmount } from "../../shared/composables/useAmount";
110
+ import { isWechat } from "../../shared/composables/useDeviceEnv";
57
111
 
58
112
  // 充值用户界面
59
113
  // 配置了必须的属性后
@@ -63,11 +117,11 @@ export interface RechargeViewProps {
63
117
  /**
64
118
  * header头中的appcode,一般情况下与app参数一致,当无应用权限时,此参数未空
65
119
  **/
66
- headerApp: string,
120
+ headerApp: string;
67
121
  /**
68
122
  * 应用
69
123
  **/
70
- app: string,
124
+ app: string;
71
125
  /**
72
126
  * 充值场景
73
127
  */
@@ -75,141 +129,226 @@ export interface RechargeViewProps {
75
129
  /**
76
130
  * 租户
77
131
  */
78
- tenant: string,
132
+ tenant: string;
79
133
  /**
80
134
  * h5支付完成后跳转地址
81
135
  */
82
- payFinishJumpUrl?: ''
136
+ payFinishJumpUrl?: "";
83
137
  }
84
138
 
85
- const props = defineProps<RechargeViewProps>()
86
- const { formatAmount } = useAmount()
87
- const { params } = useRouter()
139
+ const props = defineProps<RechargeViewProps>();
140
+ const { formatAmount } = useAmount();
141
+ const { params } = useRouter();
88
142
 
89
143
  const emit = defineEmits<{
90
- (event: 'complete', value: { result: boolean, type: string }): void,
91
- (event: 'agree'): void,
92
- }>()
144
+ (event: "complete", value: { result: boolean; type: string }): void;
145
+ (event: "agree"): void;
146
+ }>();
93
147
 
94
148
  const state = reactive({
95
149
  agreed: false,
96
150
  selected: 0,
97
151
  // agreementOpen: false,
98
152
  buttonLoading: false,
99
- })
153
+ });
100
154
 
101
-
102
- const balance = ref<number>(0)
103
- const amounts = ref<Amount[]>([])
104
- const selectBean = ref<boolean>(false)
155
+ const balance = ref<number>(0);
156
+ const amounts = ref<Amount[]>([]);
157
+ const selectBean = ref<boolean>(false);
105
158
 
106
159
  const onAgreementLinkClick = (e) => {
107
- e.preventDefault()
108
- e.stopImmediatePropagation()
109
- emit('agree')
160
+ e.preventDefault();
161
+ e.stopImmediatePropagation();
162
+ emit("agree");
110
163
  // state.agreementOpen = true
111
- }
164
+ };
112
165
 
113
166
  const onAmountSelect = (selected: number) => {
114
- state.selected = selected
115
- selectBean.value = false
116
- }
167
+ state.selected = selected;
168
+ selectBean.value = false;
169
+ };
170
+
171
+ // 计算额外支付金额(当云豆余额不足时)
172
+ const extraPaymentAmount = computed(() => {
173
+ if (!selectBean.value || !amounts.value[state.selected]) {
174
+ return 0;
175
+ }
176
+ const paymentAmount = amounts.value[state.selected].paymentAmount || 0;
177
+ const currentBalance = balance.value || 0;
178
+ return Math.max(0, paymentAmount - currentBalance);
179
+ });
117
180
 
181
+ // 计算待支付金额
118
182
  const currentAmount = computed(() => {
119
- return amounts.value[state.selected] && !selectBean.value ? amounts.value[state.selected].paymentAmount : 0
120
- })
183
+ if (!amounts.value[state.selected]) {
184
+ return 0;
185
+ }
186
+
187
+ // 如果选择了云豆支付
188
+ if (selectBean.value) {
189
+ // 如果余额不足,返回额外需要支付的金额
190
+ if (balance.value < amounts.value[state.selected].paymentAmount) {
191
+ return extraPaymentAmount.value;
192
+ }
193
+ // 如果余额充足,返回0(全部用云豆支付)
194
+ return 0;
195
+ }
196
+
197
+ // 如果没有选择云豆支付,返回全额
198
+ return amounts.value[state.selected].paymentAmount || 0;
199
+ });
200
+
201
+ // 判断是否为组合支付
202
+ const isCombinedPayment = computed(() => {
203
+ return (
204
+ selectBean.value &&
205
+ amounts.value[state.selected] &&
206
+ balance.value < amounts.value[state.selected].paymentAmount
207
+ );
208
+ });
121
209
 
122
210
  onMounted(() => {
123
- const $http = useHttp({ Appcode: props.headerApp, Tenant: props.tenant })
124
- $http.get<any[]>(endpoints.获取增值权益类目, {
125
- rightCode: props.app === 'corporateStar' ? 'riskQueryCompany' : 'riskQueryMulti',
126
- }).then((res: any) => {
127
- balance.value = res.balance
128
- amounts.value = res.paymentCaseConfigVOS
129
- })
130
- })
131
-
132
- // 云豆支付
133
- const showDialog = ref<boolean>(false)
211
+ const $http = useHttp({ Appcode: props.headerApp, Tenant: props.tenant });
212
+ $http
213
+ .get<any[]>(endpoints.获取增值权益类目, {
214
+ rightCode:
215
+ props.app === "corporateStar" ? "riskQueryCompany" : "riskQueryMulti",
216
+ })
217
+ .then((res: any) => {
218
+ balance.value = res.balance;
219
+ amounts.value = res.paymentCaseConfigVOS;
220
+ });
221
+ });
222
+
223
+ // 云豆支付对话框
224
+ const showDialog = ref<boolean>(false);
225
+
226
+ // 处理确认支付(纯云豆支付)
134
227
  async function beanPay() {
135
- const $http = useHttp({ Appcode: props.headerApp, Tenant: props.tenant })
136
- $http.post(`/payment/paymentCaseConfig/purchase/${amounts.value[state.selected].id}`).then((response: any) => {
228
+ const $http = useHttp({ Appcode: props.headerApp, Tenant: props.tenant });
229
+ try {
230
+ const response: any = await $http.post(
231
+ `/payment/paymentCaseConfig/purchase/${amounts.value[state.selected].id}`
232
+ );
137
233
  if (response) {
138
- showDialog.value = false
139
- emit('complete', { result: response, type: 'bean' })
234
+ showDialog.value = false;
235
+ emit("complete", { result: response, type: "bean" });
140
236
  } else {
141
237
  showToast({
142
- title: response.message,
143
- icon: 'none',
144
- })
238
+ title: (response as any)?.message || "支付失败",
239
+ icon: "none",
240
+ });
145
241
  }
146
- })
147
- }
148
-
149
-
150
- const onPayClick = () => {
151
- // 用云豆支付
152
- if (selectBean.value) {
153
- showDialog.value = true
154
- return
242
+ } catch (error: any) {
243
+ showToast({
244
+ title: error?.message || "支付失败",
245
+ icon: "none",
246
+ });
155
247
  }
248
+ }
156
249
 
157
- // 微信支付
158
- if (!selectBean.value && !state.agreed) {
250
+ // 执行微信支付(用于组合支付或纯微信支付)
251
+ function proceedWechatPayment() {
252
+ if (!state.agreed) {
159
253
  showToast({
160
- title: '请勾选《大道云平台云豆充值协议》',
161
- icon: 'none',
162
- })
163
- return false
254
+ title: "请勾选《大道云平台云豆充值协议》",
255
+ icon: "none",
256
+ });
257
+ return false;
164
258
  }
165
- state.buttonLoading = true
166
259
 
167
- if (Taro.getEnv() === 'WEB') {
260
+ state.buttonLoading = true;
261
+
262
+ if (Taro.getEnv() === "WEB") {
168
263
  if (!isWechat()) {
169
264
  showToast({
170
- title: '请使用微信浏览器打开',
171
- icon: 'none',
172
- })
173
- state.buttonLoading = false
174
- return false
265
+ title: "请使用微信浏览器打开",
266
+ icon: "none",
267
+ });
268
+ state.buttonLoading = false;
269
+ return false;
175
270
  }
271
+ // 组合支付或纯微信支付:传递caseConfigId和amount,后端会自动处理云豆扣减
176
272
  requestBrandWCPayByBean({
177
273
  caseConfigId: amounts.value[state.selected].id,
178
- amount: amounts.value[state.selected].paymentAmount,
179
- app: 'loankitMp',
274
+ amount: currentAmount.value,
275
+ app: "loankitMp",
180
276
  tenant: props.tenant,
181
277
  accountAuthFlag: false,
182
- channelCode: 'centergzh',
278
+ channelCode: "centergzh",
183
279
  payFinishJumpUrl: props.payFinishJumpUrl,
184
- fromMini: !!params.from
185
- }).then(result => {
186
- console.log(result, '------requestBrandWCPay')
187
- state.buttonLoading = false
188
- if (typeof result === 'boolean' && result) {
189
- window.location.href = props.payFinishJumpUrl as string
190
- } else {
191
- emit('complete', { result, type: 'wePay' })
192
- }
280
+ fromMini: !!params.from,
281
+ useCloudBean: isCombinedPayment.value
193
282
  })
283
+ .then((result) => {
284
+ state.buttonLoading = false;
285
+ if (typeof result === "boolean" && result) {
286
+ window.location.href = props.payFinishJumpUrl as string;
287
+ } else {
288
+ emit("complete", {
289
+ result,
290
+ type: isCombinedPayment.value ? "combined" : "wePay",
291
+ });
292
+ }
293
+ })
294
+ .catch((error) => {
295
+ state.buttonLoading = false;
296
+ showToast({
297
+ title: error.message || "支付失败",
298
+ icon: "none",
299
+ });
300
+ });
194
301
  } else {
195
302
  wx.login({
196
303
  success({ code }: { code: string }) {
197
- requestPaymentByBean({
198
- caseConfigId: amounts.value[state.selected].id,
199
- amount: amounts.value[state.selected].paymentAmount,
200
- app: props.app,
201
- tenant: props.tenant,
202
- user: code,
203
- }, props.headerApp).then(result => {
204
- state.buttonLoading = false
205
- if (result) {
206
- emit('complete', { result: true, type: 'wePay' })
207
- }
208
- })
209
- }
210
- })
304
+ requestPaymentByBean(
305
+ {
306
+ caseConfigId: amounts.value[state.selected].id,
307
+ amount: currentAmount.value,
308
+ app: props.app,
309
+ tenant: props.tenant,
310
+ user: code,
311
+ },
312
+ props.headerApp
313
+ )
314
+ .then((result) => {
315
+ state.buttonLoading = false;
316
+ if (result) {
317
+ emit("complete", {
318
+ result: true,
319
+ type: isCombinedPayment.value ? "combined" : "wePay",
320
+ });
321
+ }
322
+ })
323
+ .catch((error) => {
324
+ state.buttonLoading = false;
325
+ showToast({
326
+ title: error.message || "支付失败",
327
+ icon: "none",
328
+ });
329
+ });
330
+ },
331
+ fail() {
332
+ state.buttonLoading = false;
333
+ showToast({
334
+ title: "登录失败,请重试",
335
+ icon: "none",
336
+ });
337
+ },
338
+ });
211
339
  }
212
340
  }
341
+
342
+ const onPayClick = () => {
343
+ // 用云豆支付(纯云豆支付)
344
+ if (selectBean.value && !isCombinedPayment.value) {
345
+ showDialog.value = true;
346
+ return;
347
+ }
348
+
349
+ // 纯微信支付
350
+ proceedWechatPayment();
351
+ };
213
352
  </script>
214
353
 
215
354
  <style lang="scss">
@@ -226,15 +365,16 @@ const onPayClick = () => {
226
365
  .bean-buy {
227
366
  margin: 0 15px;
228
367
  padding: 10px;
229
- background: #FFFBF3;
368
+ background: #fffbf3;
230
369
  border-radius: 5px;
231
370
  display: flex;
232
371
  justify-content: space-between;
233
372
  align-items: center;
373
+ flex-wrap: wrap;
234
374
 
235
375
  .left {
236
376
  .title {
237
- color: #FD6701;
377
+ color: #fd6701;
238
378
  font-size: 14px;
239
379
  font-weight: 600;
240
380
  line-height: 20px;
@@ -245,7 +385,7 @@ const onPayClick = () => {
245
385
  color: #353535;
246
386
  font-size: 13px;
247
387
  line-height: 16px;
248
- background-image: url('https://cdn.ddjf.com/static/images/appkit/yundou.png');
388
+ background-image: url("https://cdn.ddjf.com/static/images/appkit/yundou.png");
249
389
  background-repeat: no-repeat;
250
390
  background-size: 16px 16px;
251
391
  padding-left: 24px;
@@ -272,9 +412,24 @@ const onPayClick = () => {
272
412
  }
273
413
  }
274
414
 
415
+ .balance-warning {
416
+ width: 100%;
417
+ padding: 8px 10px;
418
+ margin-top: 10px;
419
+ background: #fdefe6;
420
+ border-radius: 5px;
421
+ color: #fd6701;
422
+ font-size: 12px;
423
+
424
+ &-tip {
425
+ margin: 10px 26px 0;
426
+ color: #666666;
427
+ font-size: 10px;
428
+ }
429
+ }
430
+
275
431
  .amount-footer {
276
432
  padding: 10px 0;
277
- padding-bottom: 20px;
278
433
 
279
434
  .agreement {
280
435
  font-size: 12px;
@@ -299,7 +454,7 @@ const onPayClick = () => {
299
454
  font-size: 13px;
300
455
 
301
456
  .amount {
302
- color: #FD6701;
457
+ color: #fd6701;
303
458
  font-size: 20px;
304
459
  font-weight: 600;
305
460
 
@@ -311,7 +466,12 @@ const onPayClick = () => {
311
466
  }
312
467
 
313
468
  .recharge-button {
314
- background: linear-gradient(90deg, #FFEBC1 0%, #FFD7A7 52.29%, #FFB875 100%);
469
+ background: linear-gradient(
470
+ 90deg,
471
+ #ffebc1 0%,
472
+ #ffd7a7 52.29%,
473
+ #ffb875 100%
474
+ );
315
475
  color: #353535;
316
476
  margin: 12px 0;
317
477
  border: 0;
@@ -332,7 +492,7 @@ const onPayClick = () => {
332
492
 
333
493
  .link {
334
494
  display: inline;
335
- color: #FD6701;
495
+ color: #fd6701;
336
496
  }
337
497
  }
338
498
  }
@@ -340,7 +500,7 @@ const onPayClick = () => {
340
500
  .trade-dialog {
341
501
  .nut-dialog__header {
342
502
  font-size: 16px;
343
- color: #262626
503
+ color: #262626;
344
504
  }
345
505
 
346
506
  .item {
@@ -351,13 +511,13 @@ const onPayClick = () => {
351
511
 
352
512
  .nut-dialog__footer-cancel {
353
513
  color: #353535 !important;
354
- border-color: #CCCCCC !important;
514
+ border-color: #cccccc !important;
355
515
  }
356
516
 
357
517
  .nut-dialog__footer-ok {
358
518
  border: none;
359
519
  color: #353535;
360
- background: linear-gradient(90deg, #FFEBC1 0%, #FFB875 100%);
520
+ background: linear-gradient(90deg, #ffebc1 0%, #ffb875 100%);
361
521
  }
362
522
  }
363
523
  </style>
@@ -117,6 +117,8 @@ const requestBrandWCPayByBean = (params: PaymentParams, Appcode = '') => {
117
117
  }
118
118
  })
119
119
  }
120
+ }).catch(() => {
121
+ resolve(false)
120
122
  })
121
123
  })
122
124
  }
@@ -28,6 +28,7 @@ export type PaymentParams = {
28
28
  payFinishJumpUrl?: string
29
29
  fromMini?: Boolean
30
30
  clientInfo?: string
31
+ useCloudBean?: boolean
31
32
  }
32
33
 
33
34
  export type RechargeParams = Pick<PaymentParams, 'app' | 'tenant'>