Browse Source

fix: validate enabled payment methods

Pchen. 1 week ago
parent
commit
33dad94055

+ 8 - 0
src/api/order.js

@@ -6,6 +6,7 @@ const api = {
   Cancel: '/Order/CancelOrder',
   Cancel: '/Order/CancelOrder',
   Refund: '/Order/RefundOrder',
   Refund: '/Order/RefundOrder',
   Detail: '/Order/Detail',
   Detail: '/Order/Detail',
+  PaymentMethods: '/Order/PaymentMethods',
   GetMyOrder: '/Order/GetMyOrders',
   GetMyOrder: '/Order/GetMyOrders',
   AdminOrderList: '/Admin/Order/List',
   AdminOrderList: '/Admin/Order/List',
   AdminOrderDetail: '/Admin/Order/Detail',
   AdminOrderDetail: '/Admin/Order/Detail',
@@ -36,6 +37,13 @@ export function orderDeatil(parameter) {
   })
   })
 }
 }
 
 
+export function getPaymentMethods() {
+  return request({
+    url: api.PaymentMethods,
+    method: 'get'
+  })
+}
+
 export function cancelOrder(parameter) {
 export function cancelOrder(parameter) {
   return request({
   return request({
     url: api.Cancel,
     url: api.Cancel,

+ 2 - 1
src/components/store/PayMethodPicker.vue

@@ -32,11 +32,12 @@ const defaultMethods = [
 const props = defineProps({
 const props = defineProps({
   modelValue: { type: String, default: '' },
   modelValue: { type: String, default: '' },
   methods: { type: Array, default: () => [] },
   methods: { type: Array, default: () => [] },
+  fallbackDefault: { type: Boolean, default: true },
   layout: { type: String, default: 'stack' }
   layout: { type: String, default: 'stack' }
 })
 })
 
 
 const methods = computed(() => {
 const methods = computed(() => {
-  const source = props.methods.length ? props.methods : defaultMethods
+  const source = props.methods.length ? props.methods : (props.fallbackDefault ? defaultMethods : [])
   return source.map(item => ({
   return source.map(item => ({
     value: item.value || item.type,
     value: item.value || item.type,
     label: item.label || item.name || item.type,
     label: item.label || item.name || item.type,

+ 36 - 3
src/pages/store/goodsDetail/index.vue

@@ -109,7 +109,10 @@
 
 
       <div class="checkout-section">
       <div class="checkout-section">
         <div class="checkout-section__title">选择支付方式</div>
         <div class="checkout-section__title">选择支付方式</div>
-        <PayMethodPicker v-model="payType" />
+        <PayMethodPicker v-model="payType" :methods="paymentMethods" :fallback-default="false" />
+        <p v-if="paymentMethods.length === 0" class="payment-method-empty">
+          暂无可用支付方式,请稍后再试或联系管理员
+        </p>
       </div>
       </div>
 
 
       <template #footer>
       <template #footer>
@@ -132,7 +135,7 @@
 <script setup>
 <script setup>
 import { ref, computed } from 'vue'
 import { ref, computed } from 'vue'
 import { getGoods } from '@/api/goods'
 import { getGoods } from '@/api/goods'
-import { createOrder } from '@/api/order'
+import { createOrder, getPaymentMethods } from '@/api/order'
 import { validateCoupon } from '@/api/coupon'
 import { validateCoupon } from '@/api/coupon'
 import { useRoute, useRouter } from 'vue-router'
 import { useRoute, useRouter } from 'vue-router'
 import { Notification, Message } from '@arco-design/web-vue'
 import { Notification, Message } from '@arco-design/web-vue'
@@ -157,6 +160,7 @@ const couponCode = ref('')
 const couponApplied = ref(null)
 const couponApplied = ref(null)
 const couponLoading = ref(false)
 const couponLoading = ref(false)
 const couponError = ref('')
 const couponError = ref('')
+const paymentMethods = ref([])
 
 
 const featureList = computed(() => parseFeatures(data.value?.features))
 const featureList = computed(() => parseFeatures(data.value?.features))
 
 
@@ -166,7 +170,7 @@ const payablePrice = computed(() => {
 })
 })
 
 
 const openCheckout = () => {
 const openCheckout = () => {
-  payType.value = ''
+  payType.value = paymentMethods.value[0]?.type || ''
   couponCode.value = ''
   couponCode.value = ''
   couponApplied.value = null
   couponApplied.value = null
   couponError.value = ''
   couponError.value = ''
@@ -201,10 +205,19 @@ const applyCoupon = async () => {
 }
 }
 
 
 const submitOrder = async () => {
 const submitOrder = async () => {
+  if (paymentMethods.value.length === 0) {
+    Message.warning('暂无可用支付方式,请稍后再试')
+    return
+  }
   if (!payType.value) {
   if (!payType.value) {
     Message.warning('请选择支付方式')
     Message.warning('请选择支付方式')
     return
     return
   }
   }
+  if (!paymentMethods.value.some(method => method.type === payType.value)) {
+    Message.warning('该支付方式当前不可用,请重新选择')
+    payType.value = paymentMethods.value[0]?.type || ''
+    return
+  }
   const paymentWindow = window.open('', '_blank')
   const paymentWindow = window.open('', '_blank')
   if (!paymentWindow) {
   if (!paymentWindow) {
     Message.warning('浏览器拦截了支付页弹窗,请允许弹窗后重试')
     Message.warning('浏览器拦截了支付页弹窗,请允许弹窗后重试')
@@ -216,6 +229,7 @@ const submitOrder = async () => {
     if (couponApplied.value?.code) payload.coupon_code = couponApplied.value.code
     if (couponApplied.value?.code) payload.coupon_code = couponApplied.value.code
     const res = await createOrder(payload)
     const res = await createOrder(payload)
     if (!res || res.code !== 0) {
     if (!res || res.code !== 0) {
+      if (paymentWindow && !paymentWindow.closed) paymentWindow.close()
       Notification.error({
       Notification.error({
         title: '创建订单失败',
         title: '创建订单失败',
         content: res?.msg ?? '请稍后再试'
         content: res?.msg ?? '请稍后再试'
@@ -267,7 +281,20 @@ const getGoodsDetail = async () => {
   }
   }
 }
 }
 
 
+const loadPaymentMethods = async () => {
+  try {
+    const res = await getPaymentMethods()
+    paymentMethods.value = Array.isArray(res?.data) ? res.data : []
+    if (!paymentMethods.value.some(method => method.type === payType.value)) {
+      payType.value = paymentMethods.value[0]?.type || ''
+    }
+  } catch (error) {
+    paymentMethods.value = []
+  }
+}
+
 getGoodsDetail()
 getGoodsDetail()
+loadPaymentMethods()
 </script>
 </script>
 
 
 <style lang="less" scoped>
 <style lang="less" scoped>
@@ -482,6 +509,12 @@ getGoodsDetail()
   color: @store-accent;
   color: @store-accent;
 }
 }
 
 
+.payment-method-empty {
+  margin: 8px 0 0;
+  font-size: 12px;
+  color: rgb(var(--orange-6));
+}
+
 .checkout-order__row--discount .discount {
 .checkout-order__row--discount .discount {
   color: rgb(var(--green-6));
   color: rgb(var(--green-6));
   font-weight: 600;
   font-weight: 600;

+ 31 - 3
src/pages/store/orders/orderDetail/index.vue

@@ -38,13 +38,21 @@
           title="选择支付方式"
           title="选择支付方式"
         >
         >
           <!-- <p class="payment-method-card__hint">可以随时切换,确认后将直接跳转至对应支付页面。</p> -->
           <!-- <p class="payment-method-card__hint">可以随时切换,确认后将直接跳转至对应支付页面。</p> -->
-          <PayMethodPicker v-model="selectedPayType" :methods="availablePaymentMethods" layout="grid" />
+          <PayMethodPicker
+            v-model="selectedPayType"
+            :methods="availablePaymentMethods"
+            :fallback-default="false"
+            layout="grid"
+          />
+          <p v-if="availablePaymentMethods.length === 0" class="payment-method-card__empty">
+            暂无可用支付方式,请稍后再试或联系管理员
+          </p>
           <a-button
           <a-button
             type="primary"
             type="primary"
             long
             long
             size="large"
             size="large"
             class="payment-method-card__submit"
             class="payment-method-card__submit"
-            :disabled="!selectedPayType"
+            :disabled="!selectedPayType || availablePaymentMethods.length === 0"
             :loading="payLoading"
             :loading="payLoading"
             @click="pay"
             @click="pay"
           >
           >
@@ -252,7 +260,12 @@ const getOrderDetail = async () => {
     data.value = res.data ?? {}
     data.value = res.data ?? {}
     content.value = decodeGoodsContent(res.data?.content)
     content.value = decodeGoodsContent(res.data?.content)
     if (data.value?.state === 0 && !selectedPayType.value) {
     if (data.value?.state === 0 && !selectedPayType.value) {
-      selectedPayType.value = data.value.pay_type || availablePaymentMethods.value[0]?.type || 'alipay'
+      selectedPayType.value = availablePaymentMethods.value.some(method => method.type === data.value.pay_type)
+        ? data.value.pay_type
+        : availablePaymentMethods.value[0]?.type || ''
+    }
+    if (data.value?.state === 0 && selectedPayType.value && !availablePaymentMethods.value.some(method => method.type === selectedPayType.value)) {
+      selectedPayType.value = availablePaymentMethods.value[0]?.type || ''
     }
     }
     updateStepState()
     updateStepState()
   } catch (error) {
   } catch (error) {
@@ -323,10 +336,19 @@ onUnmounted(() => {
 })
 })
 
 
 const pay = async () => {
 const pay = async () => {
+  if (availablePaymentMethods.value.length === 0) {
+    Message.warning('暂无可用支付方式,请稍后再试')
+    return
+  }
   if (!selectedPayType.value) {
   if (!selectedPayType.value) {
     Message.warning('请选择支付方式')
     Message.warning('请选择支付方式')
     return
     return
   }
   }
+  if (!availablePaymentMethods.value.some(method => method.type === selectedPayType.value)) {
+    Message.warning('该支付方式当前不可用,请重新选择')
+    selectedPayType.value = availablePaymentMethods.value[0]?.type || ''
+    return
+  }
   const paymentWindow = window.open('', '_blank')
   const paymentWindow = window.open('', '_blank')
   if (!paymentWindow) {
   if (!paymentWindow) {
     Message.warning('浏览器拦截了支付页弹窗,请允许弹窗后重试')
     Message.warning('浏览器拦截了支付页弹窗,请允许弹窗后重试')
@@ -518,6 +540,12 @@ const handleRefundOrder = () => {
     border-color: transparent !important;
     border-color: transparent !important;
     box-shadow: 0 8px 18px fade(@store-primary, 24%);
     box-shadow: 0 8px 18px fade(@store-primary, 24%);
   }
   }
+
+  &__empty {
+    margin: 10px 0 0;
+    font-size: 12px;
+    color: rgb(var(--orange-6));
+  }
 }
 }
 
 
 .status-badge-wrap {
 .status-badge-wrap {