Переглянути джерело

feat: 修改商品下单跳转逻辑及交互

liangan 4 тижнів тому
батько
коміт
be1aab6521

+ 28 - 32
src/components/DialogBox/DialogBox.vue

@@ -8,6 +8,8 @@ interface Props {
   type?: DialogType
   /** 确认按钮文本 */
   confirmText?: string
+  // 按钮样式
+  confirmPlain?: boolean
   /** 取消按钮文本 */
   cancelText?: string
   /** 图标大小 */
@@ -48,6 +50,7 @@ const props = withDefaults(defineProps<Props>(), {
   showConfirm: true,
   showCancel: false,
   showTip: false,
+  confirmPlain: true,
   closeOnClickOverlay: true,
 })
 
@@ -92,48 +95,40 @@ function handleCancel() {
 <template>
   <wd-overlay :show="props.show" @click="handleOverlayClick">
     <view class="wrapper">
-      <view class="rounded-24rpx bg-white p-40rpx text-center" @click.stop>
-        <image
-          :src="iconSrc"
-          :style="{ width: props.iconSize, height: props.iconSize }"
-        />
-        <view class="pb-58rpx pt-34rpx text-center text-32rpx">
-          {{ props.message }}
-        </view>
+      <view class="w-full rounded-24rpx bg-white p-40rpx text-center" @click.stop>
+        <slot>
+          <image
+            :src="iconSrc"
+            :style="{ width: props.iconSize, height: props.iconSize }"
+          />
+          <view class="pb-58rpx pt-34rpx text-center text-32rpx">
+            {{ props.message }}
+          </view>
+        </slot>
 
         <!-- 按钮区域 -->
         <view class="button-container">
-          <!-- 只有确认按钮时居中显示 -->
+          <!-- 有取消按钮时并排显示 -->
           <wd-button
-            v-if="props.showConfirm && !props.showCancel"
+            v-if="props.showCancel"
+            class="button-half"
             plain
             block
+            custom-class="text-#333! border-#333!"
+            @click="handleCancel"
+          >
+            {{ props.cancelText }}
+          </wd-button>
+          <wd-button
+            v-if="props.showConfirm"
+            :plain="props.confirmPlain"
+            block
+            class="button-half"
+            type="primary"
             @click="handleConfirm"
           >
             {{ props.confirmText }}
           </wd-button>
-
-          <!-- 有取消按钮时并排显示 -->
-          <template v-if="props.showConfirm && props.showCancel">
-            <wd-button
-              class="button-half"
-              plain
-              block
-              custom-class="text-#333! border-#333!"
-              @click="handleCancel"
-            >
-              {{ props.cancelText }}
-            </wd-button>
-            <wd-button
-              plain
-              block
-              class="button-half"
-              type="primary"
-              @click="handleConfirm"
-            >
-              {{ props.confirmText }}
-            </wd-button>
-          </template>
         </view>
 
         <view v-if="props.showTip && props.tip" class="mt-20rpx text-24rpx text-gray-500">
@@ -151,6 +146,7 @@ function handleCancel() {
   justify-content: center;
   height: 100%;
   padding: 0 24rpx;
+  width: 702rpx;
 }
 
 .button-container {

+ 1 - 0
src/components/DialogBox/utils.ts

@@ -4,6 +4,7 @@ interface DialogBoxProps {
   show?: boolean
   type?: DialogType
   confirmText?: string
+  confirmPlain?: boolean
   cancelText?: string
   iconSize?: string
   message?: string

+ 0 - 3
src/pages/mine/addressBookOperate.vue

@@ -23,9 +23,6 @@ defineOptions({
   name: 'AddressBookOperate', // 地址簿新增&编辑
 })
 
-const userInfo = computed(() => {
-  return getUserInfoHook()
-})
 // z-paging
 const paging = ref(null)
 // 类似mixins,如果是页面滚动务必要写这一行,并传入当前ref绑定的paging,注意此处是paging,而非paging.value

+ 118 - 27
src/pages/myOrders/orderDetail.vue

@@ -11,12 +11,13 @@
 <script lang="ts" setup>
 import { getConfigByCode } from '@/api/common'
 import { orderCancel, orderDetail, orderPink, orderStatusEnum, payOrder } from '@/api/order'
+import { getWalletAccountInfo } from '@/api/wallet'
 import DialogBox from '@/components/DialogBox/DialogBox.vue'
 import { DialogUtils } from '@/components/DialogBox/utils'
 import { t } from '@/locale'
 import { formatNumber } from '@/utils'
 import { getPageParams, toPage } from '@/utils/page'
-import { showToast, toast } from '@/utils/toast'
+import { toast } from '@/utils/toast'
 
 defineOptions({
   name: 'OrderDetail', // 订单详情
@@ -26,6 +27,7 @@ defineOptions({
 const paging = ref(null)
 
 const id = ref<any>()
+const isPayOrder = ref<boolean>(false)
 const detail = ref<any>({})
 const orderStatusEnumData = ref<any>([])
 const openRedEnvelopeRate = ref<any>()
@@ -35,6 +37,7 @@ const timer = ref()
 
 // DialogBox 函数式调用配置
 const dialogConfig = ref<any>({})
+const dialogType = ref<'cancel' | 'pay' | 'recharge' | ''>('')
 
 async function getConfig(code: string) {
   try {
@@ -107,7 +110,13 @@ async function getDetail() {
     const res = await orderDetail({ id: id.value })
     if (res.code === '200') {
       detail.value = res.data
-      startCountdown() // 开始倒计时
+      if (detail.value?.status === 1) {
+        startCountdown() // 开始倒计时
+        // if (isPayOrder.value) {
+        //   // 自动调用支付接口
+        //   await goPay()
+        // }
+      }
       await getPink()
       paging.value.complete()
     }
@@ -139,12 +148,14 @@ function selectAddress() {
 
 // 显示取消订单确认对话框
 function showCancelOrderDialog() {
+  dialogType.value = 'cancel'
   Object.assign(dialogConfig.value, DialogUtils.info(
     t('orderDetail.dialog.cancel.title'),
     {
       showCancel: true,
       confirmText: t('orderDetail.dialog.cancel.confirm'),
       cancelText: t('orderDetail.dialog.cancel.keep'),
+      confirmPlain: true,
     },
   ))
 }
@@ -183,14 +194,15 @@ async function cancelOrder() {
 
 // 处理对话框确认事件
 function handleDialogConfirm() {
-  const config = dialogConfig.value as any
-  const { confirmText } = config
-
-  if (confirmText === 'Yes, Cancel') {
-    // 确认取消订单
+  if (dialogType.value === 'cancel') {
     cancelOrder()
   }
-
+  else if (dialogType.value === 'pay') {
+    goPay()
+  }
+  else if (dialogType.value === 'recharge') {
+    toPage('/pages/wallet/recharge', { price: detail.value?.payPrice }, true)
+  }
   // 关闭对话框
   handleDialogClose()
 }
@@ -199,22 +211,49 @@ function handleDialogConfirm() {
 function handleDialogClose() {
   dialogConfig.value.show = false
 }
+// 支付
+// 显示支付余额去充值提示
+function showRechargeDialog() {
+  dialogType.value = 'recharge'
+  Object.assign(dialogConfig.value, DialogUtils.info(
+    `Your wallet balance is insufficient. \n Please Recharge!`,
+    {
+      showCancel: false,
+      confirmText: 'Recharge Now',
+      cancelText: '',
+      confirmPlain: true,
+    },
+  ))
+}
+// 显示支付确认对话框
+function showPayOrderDialog() {
+  dialogType.value = 'pay'
+  Object.assign(dialogConfig.value, DialogUtils.info(
+    'BandhuBuy Wallet Pay',
+    {
+      showCancel: false,
+      cancelText: '',
+      confirmText: 'DONE',
+      confirmPlain: false,
+    },
+  ))
+}
+async function goPay() {
+  const payRes = await payOrder({
+    orderId: detail.value?.orderId,
+    type: detail.value?.storePink?.kId ? 'open' : 'join',
+  })
+  console.log(payRes)
+  if (payRes.code === '200') {
+    toast.success(t('orderDetail.payment.success'))
+    getDetail()
+  }
+}
 
-async function handleClick() {
+function handleClick() {
   if (detail.value?.status === 1) {
     // 去支付
-    const payRes = await payOrder({
-      orderId: detail.value?.orderId,
-      type: detail.value?.storePink?.kId ? 'open' : 'join',
-    })
-    console.log(payRes)
-    if (payRes.code === '200') {
-      showToast({
-        message: t('orderDetail.payment.success'),
-        icon: 'success',
-      })
-      getDetail()
-    }
+    showPayOrderDialog()
   }
   else {
     // 去分享
@@ -231,10 +270,25 @@ onLoad(async (options) => {
   getConfig('join_red_envelope_rate')
   const params = getPageParams(options)
   id.value = params.id
+  isPayOrder.value = params.isPayOrder
   await getOrderStatus()
 })
-onShow(() => {
-  getDetail()
+const balance = ref<number>(0)
+onShow(async () => {
+  await getDetail()
+  if (isPayOrder.value && detail.value?.status === 1) {
+    const res = await getWalletAccountInfo()
+    console.log(res)
+    balance.value = res?.data?.balance
+    if (balance.value < detail.value?.payPrice) {
+      // 余额不足,提示去充值
+      showRechargeDialog()
+    }
+    else {
+      // 余额充足,显示支付对话框
+      showPayOrderDialog()
+    }
+  }
 })
 
 onUnmounted(() => {
@@ -382,7 +436,7 @@ onUnmounted(() => {
       </view>
     </view>
     <template #bottom>
-      <view class="flex items-center justify-end bg-white/60 px-28rpx py-30rpx backdrop-blur-20">
+      <view v-if="detail?.status === 1" class="flex items-center justify-end bg-white/60 px-28rpx py-30rpx backdrop-blur-20">
         <!-- 取消订单按钮 -->
         <wd-button
           v-if="detail?.status === 1"
@@ -393,18 +447,55 @@ onUnmounted(() => {
           {{ t('orderDetail.button.cancel') }}
         </wd-button>
         <wd-button @click="handleClick">
-          {{ detail?.status !== 1 ? t('orderDetail.button.share') : t('orderDetail.button.pay') }}
+          {{ t('orderDetail.button.pay') }}
         </wd-button>
       </view>
     </template>
-
     <!-- DialogBox 函数式调用 -->
     <DialogBox
       v-bind="dialogConfig"
       @confirm="handleDialogConfirm"
       @cancel="handleDialogClose"
       @close="handleDialogClose"
-    />
+    >
+      <view v-if="dialogType === 'pay'">
+        <view class="font-blod relative text-32rpx">
+          <text>BandhuBuy Wallet Pay</text>
+          <wd-icon name="close-normal" custom-class="absolute right-0 top-1/2 -translate-y-1/2" size="40rpx" @click="handleDialogClose" />
+        </view>
+        <view class="py-60rpx">
+          <text class="text-40rpx">
+            ৳
+          </text>
+          <text class="text-60rpx">
+            {{ formatNumber(detail.payPrice) }}
+          </text>
+        </view>
+        <view class="pb-28rpx text-left">
+          <view class="text-24rpx font-bold">
+            Payment Method
+          </view>
+          <view class="my-14rpx border-b-1px border-b-#EBEBEB border-b-solid" />
+          <view class="flex items-center justify-between text-24rpx">
+            <view class="flex items-center">
+              <view class="text-24rpx">
+                <text>BandhuBuy Wallet (</text>
+                <text class="text-[var(--wot-color-theme)]">
+                  Balance: ৳{{ formatNumber(balance) }}
+                </text>
+                <text>)</text>
+              </view>
+            </view>
+            <view>
+              <image
+                src="/static/icons/circle-check.png"
+                class="h-36rpx w-36rpx"
+              />
+            </view>
+          </view>
+        </view>
+      </view>
+    </DialogBox>
   </z-paging>
 </template>
 

+ 4 - 92
src/pages/productDetail/checkOut.vue

@@ -10,22 +10,15 @@
 </route>
 
 <script lang="ts" setup>
-import { computedPrice, createOrder, loadPre, payOrder } from '@/api/order'
+import { computedPrice, createOrder, loadPre } from '@/api/order'
 import { getWalletAccountInfo } from '@/api/wallet'
-import DialogBox from '@/components/DialogBox/DialogBox.vue'
-import { DialogUtils } from '@/components/DialogBox/utils'
-import { t } from '@/locale'
-import { useUserStore } from '@/store'
 import { formatNumber } from '@/utils'
 import { getPageParams, toPage } from '@/utils/page'
 
 defineOptions({
   name: 'CheckOut', // 结账页面
 })
-const userStore = useUserStore()
-const userInfo = computed(() => {
-  return userStore.userInfo
-})
+
 const queryParams = ref<any>({})
 onLoad((options) => {
   const params = getPageParams(options)
@@ -60,42 +53,6 @@ async function getPrice() {
   walletBalance.value = walletInfoRes?.data?.balance
 }
 
-// 支付方式
-const paymentMethods = ref([
-  {
-    id: 'bandhubuy',
-    name: 'BandhuBuy Wallet',
-    balance: 2000.00,
-    selected: true,
-    icon: '/static/icons/wallet-icon.png',
-  },
-])
-
-// 选中的支付方式
-const selectedPayment = ref('bandhubuy')
-
-// DialogBox 函数式调用配置
-const dialogConfig = ref({})
-
-// 处理支付方式选择
-function selectPayment(methodId: string) {
-  selectedPayment.value = methodId
-  paymentMethods.value.forEach((method) => {
-    method.selected = method.id === methodId
-  })
-}
-
-// 显示余额不足对话框
-function showInsufficientBalanceDialog() {
-  Object.assign(dialogConfig.value, DialogUtils.info(
-    t('checkout.dialog.insufficientBalance'),
-    {
-      tip: t('checkout.dialog.rechargeDiscount'),
-      showTip: true,
-      confirmText: t('checkout.dialog.rechargeNow'),
-    },
-  ))
-}
 const loading = ref<boolean>(false)
 // 下单处理
 async function handlePlaceOrder() {
@@ -111,51 +68,13 @@ async function handlePlaceOrder() {
     const orderRes = await createOrder(params)
     console.log(orderRes)
     if (orderRes.code === '200') {
-      const payRes = await payOrder({
-        orderId: orderRes?.data?.columns?.orderNo,
-        type: queryParams.value.groupType,
-      })
-      console.log(payRes)
-      if (payRes.code === '8000') {
-        showInsufficientBalanceDialog()
-      }
-      else {
-        toPage('/pages/myOrders/myOrders', {}, true)
-      }
+      toPage('/pages/myOrders/orderDetail', { id: orderRes?.data?.columns?.orderId, isPayOrder: true }, true)
     }
   }
   finally {
     loading.value = false
   }
 }
-
-// 处理对话框确认事件
-function handleDialogConfirm() {
-  const config = dialogConfig.value as any
-  const { type, confirmText } = config
-
-  // 根据确认按钮文本判断是哪种对话框
-  if (confirmText === t('checkout.dialog.rechargeNow')) {
-    // 余额不足,跳转到充值页面
-    uni.navigateTo({ url: '/pages/wallet/recharge' })
-  }
-  else if (type === 'success') {
-    // 支付成功,跳转到订单页面
-    uni.showToast({ title: t('checkout.toast.redirecting'), icon: 'none' })
-  }
-  else if (type === 'error') {
-    // 支付失败或网络错误,重新尝试
-    uni.showToast({ title: t('checkout.toast.retrying'), icon: 'loading' })
-  }
-
-  // 关闭对话框
-  dialogConfig.value = {}
-}
-
-// 处理对话框关闭事件
-function handleDialogClose() {
-  dialogConfig.value = {}
-}
 </script>
 
 <template>
@@ -205,7 +124,7 @@ function handleDialogClose() {
           <view class="flex items-center justify-between text-24rpx">
             <view class="flex items-center">
               <image
-                :src="userInfo.headPic"
+                src="/static/icons/logo.png"
                 class="mr-32rpx h-68rpx w-68rpx rounded-full"
               />
               <view class="text-24rpx">
@@ -239,13 +158,6 @@ function handleDialogClose() {
         </wd-button>
       </view>
     </template>
-
-    <!-- DialogBox 函数式调用 -->
-    <DialogBox
-      v-bind="dialogConfig"
-      @confirm="handleDialogConfirm"
-      @close="handleDialogClose"
-    />
   </z-paging>
 </template>
 

+ 56 - 7
src/pages/wallet/recharge.vue

@@ -22,11 +22,15 @@
 <script lang="ts" setup>
 import { paymentMethod, rechargeAdd, rechargeGoodsList } from '@/api/wallet'
 import { formatNumber } from '@/utils'
-import { toPage } from '@/utils/page'
+import { getPageParams, toPage } from '@/utils/page'
+import { toast } from '@/utils/toast'
 
 defineOptions({
   name: 'Recharge', // 充值
 })
+
+const orderPrice = ref(0) // 商品订单金额
+
 const selectData = ref<any>({
   methodId: '',
   id: '',
@@ -64,7 +68,7 @@ async function getRechargeGoodsList(id?: string) {
     dataList.value = res.data.list
     interval.value = {
       maxPrice: res.data.maxPrice,
-      miniPrice: res.data.miniPrice,
+      miniPrice: orderPrice.value || res.data.miniPrice,
     }
   }
 }
@@ -83,12 +87,25 @@ function focusAmount() {
 const loading = ref<boolean>(false)
 
 async function submit() {
+  const amount = Number(selectData.value.customAmount || selectData.value.amount)
+  if (!amount) {
+    toast.info('请输入充值金额')
+    return
+  }
+  if (amount < interval.value.miniPrice) {
+    toast.info(`最小充值金额为 ${interval.value.miniPrice}`)
+    return
+  }
+  if (amount > interval.value.maxPrice) {
+    toast.info(`最大充值金额为 ${interval.value.maxPrice}`)
+    return
+  }
+
   loading.value = true
   try {
-    const amount = selectData.value.customAmount || selectData.value.amount
     const addRes = await rechargeAdd({ amount, methodId: selectData.value.methodId })
     if (addRes.code === '200') {
-      toPage('/pages/webLink/webLink', { link: addRes.data.payUrl }, true)
+      toPage('/pages/webLink/webLink', { link: addRes.data.payUrl, title: 'Recharge' }, true)
     }
   }
   finally {
@@ -99,6 +116,29 @@ async function submit() {
 onShow(() => {
   getMethodList()
 })
+onLoad((options) => {
+  const params = getPageParams(options)
+  orderPrice.value = params.price || 0
+})
+
+// 监听自定义金额变化
+watch(() => selectData.value.customAmount, (newVal) => {
+  if (!newVal)
+    return
+
+  // 移除非数字字符
+  const numericValue = newVal.toString().replace(/\D/g, '')
+  if (numericValue !== newVal) {
+    selectData.value.customAmount = numericValue
+    return
+  }
+
+  const amount = Number(numericValue)
+  if (amount > interval.value.maxPrice) {
+    selectData.value.customAmount = interval.value.maxPrice.toString()
+    toast.info(`最大充值金额为 ${interval.value.maxPrice}`)
+  }
+})
 </script>
 
 <template>
@@ -132,11 +172,12 @@ onShow(() => {
         <view
           v-for="i in dataList"
           :key="i.id"
-          class="border-1 border-transparent rounded-12rpx border-solid bg-white py-22rpx text-center"
+          class="amount-item border-1 border-transparent rounded-12rpx border-solid bg-white py-22rpx text-center"
+          :class="{ disabled: orderPrice && i.amount < orderPrice }"
           :style="{
             borderColor: i.id === selectData.id ? 'var(--wot-color-theme)' : '',
           }"
-          @click="handleSelectAmount(i)"
+          @click="!orderPrice || i.amount >= orderPrice ? handleSelectAmount(i) : null"
         >
           <view>
             <text class="text-24rpx">
@@ -170,4 +211,12 @@ onShow(() => {
   </z-paging>
 </template>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.amount-item {
+  box-shadow: 0rpx 2rpx 8rpx 0rpx rgba(184, 184, 184, 0.5);
+  &.disabled {
+    cursor: not-allowed;
+    background-color: rgba(184, 184, 184, 0.5);
+  }
+}
+</style>