Selaa lähdekoodia

feat(api): 修复海博订单状态类型定义

- 将 hbOrderStatus 字段从可选改为必选

refactor(components): 优化CollapsePanel组件代码结构

- 移除不必要的注释
- 添加pb20rpx样式类

feat(afterSales): 实现售后订单功能

- 添加订单列表响应式数据
- 实现页面加载时解析订单参数
- 添加商品列表渲染逻辑
- 实现选择商品功能

fix(classfiy): 修复商品分类页面滚动逻辑

- 调整商品滚动定位条件判断
- 优化加载状态显示逻辑
- 修改滚动阈值和样式

fix(confirmOrder): 修复支付流程问题

- 支付成功和失败处理改为异步执行
- 添加按钮禁用状态防止重复点击

fix(goods): 修复商品页面按钮状态

- 添加按钮禁用状态防止重复点击

feat(order): 增加订单售后功能

- 实现申请售后功能
- 调整订单状态显示逻辑
- 添加售后页面跳转

feat(search): 优化搜索结果页面

- 添加商品售罄状态显示
- 优化价格显示布局

refactor(utils): 优化支付成功失败处理逻辑

- 将支付成功失败处理改为Promise形式
- 添加延时处理确保页面跳转
zhangtao 1 viikko sitten
vanhempi
commit
3ea7b8f65e

+ 1 - 1
src/api/api.type.d.ts

@@ -615,7 +615,7 @@ namespace Api {
      * 海博订单状态:0-待支付,1-待发货(快递使用),20-订单已接单(待拣货),30-订单待配送(拣货完成/自提类订单为待自提),40-订单配送中
      * ,50-订单取消待审核,60-订单已取消,70-订单已送达,80-订单已完成
      */
-    hbOrderStatus?: number
+    hbOrderStatus: number
     /**
      * 是否已经支付,1:已经支付过,0:,没有支付过
      */

+ 1 - 8
src/components/CollapsePanel.vue

@@ -25,12 +25,10 @@ const emit = defineEmits<{
 
 const _this = getCurrentInstance()
 
-// 响应式数据
 const isExpanded = ref(props.defaultExpanded)
 const contentHeight = ref(0)
 const showToggle = ref(false)
 
-// 计算属性
 const toggleText = computed(() =>
   isExpanded.value ? props.collapseText : props.expandText,
 )
@@ -38,7 +36,6 @@ const toggleText = computed(() =>
 const contentStyle = computed(() => {
   const style: Record<string, string> = {}
   if (isExpanded.value) {
-    // 展开状态,不限制高度
     style.overflow = 'visible'
   }
   else {
@@ -50,13 +47,11 @@ const contentStyle = computed(() => {
   return style
 })
 
-// 方法
 function handleToggle() {
   isExpanded.value = !isExpanded.value
   emit('toggle', isExpanded.value)
 }
 
-// 获取内容高度
 function getContentHeight() {
   return new Promise<number>((resolve) => {
     const query = uni.createSelectorQuery().in(_this)
@@ -72,7 +67,6 @@ function getContentHeight() {
   })
 }
 
-// 检查是否需要显示展开按钮
 async function checkNeedToggle() {
   await nextTick()
 
@@ -110,7 +104,6 @@ watch(() => props.inline, () => {
 })
 
 onMounted(() => {
-  // 使用setTimeout确保DOM已渲染
   setTimeout(() => {
     checkNeedToggle()
   }, 100)
@@ -120,7 +113,7 @@ onMounted(() => {
 <template>
   <view class="collapse-panel">
     <view
-      class="collapse-panel__content"
+      class="collapse-panel__content pb20rpx"
       :class="{
         'collapse-panel__content--collapsed': !isExpanded,
         'collapse-panel__content--expanded': isExpanded,

+ 30 - 14
src/subPack-common/afterSales/index.vue

@@ -24,6 +24,17 @@ const resonList = [
   { id: 5, name: '商品临期到期' },
   { id: 6, name: '商品破损/包装破损' },
 ]
+const orderList = ref<Api.xsbOmsOrderItem[]>([])
+onLoad((options: any) => {
+  orderList.value = JSON.parse(options.order)
+  if (orderList.value.length) {
+    orderList.value.map((it) => {
+      it.num = undefined
+      return it
+    })
+  }
+})
+
 function handleSubmit() {
   console.log(fileList.value, 'fileList')
   router.push({ name: 'xsb-afterSalesDetail' })
@@ -34,6 +45,10 @@ function handleSelectReson() {
   showReson.value = false
   resonName.value = resonList.find(item => item.id === resonId.value)?.name || '请选择退款原因'
 }
+
+watch(() => orderList.value, () => {
+  console.log(orderList.value, '=============')
+})
 </script>
 
 <template>
@@ -93,35 +108,36 @@ function handleSelectReson() {
         <view class="goods mt24rpx">
           <CollapsePanel :line-height="150">
             <wd-checkbox-group v-model="selectGoods">
-              <view v-for="item in 10" :key="item" class="mb20rpx">
-                <wd-checkbox :model-value="item">
-                  <view class="w-full flex items-center">
+              <template v-for="item in orderList" :key="item.skuId">
+                <view class="mb20rpx flex items-center justify-between">
+                  <wd-checkbox :model-value="item.skuId" />
+                  <view class="box-border w-full flex items-center">
                     <image :src="`${StaticUrl}/shu.png`" class="h120rpx w120rpx flex-shrink-0" />
-                    <view class="ml20rpx flex-1">
-                      <view class="flex items-center justify-between">
-                        <view class="text-28rpx">
-                          赶海季生鲜大闸蟹
+                    <view class="ml20rpx box-border flex-1">
+                      <view class="w-full flex justify-between">
+                        <view class="max-w-320rpx whitespace-pre-wrap break-words break-all text-28rpx">
+                          {{ item.prodName }}
                         </view>
-                        <view class="text-32rpx text-#FF4D3A font-semibold">
-                          ¥103.95
+                        <view class="w30% flex-shrink-0 text-32rpx text-#FF4D3A font-semibold">
+                          ¥{{ item.productTotalAmount }}
                         </view>
                       </view>
                       <view class="text-24rpx text-#AAAAAA">
-                        规格:5kg,盒
+                        规格:{{ item.spec }}
                       </view>
                       <view class="flex items-center justify-between">
                         <view class="text-24rpx text-#AAAAAA">
-                          单价:¥1.8
+                          单价:¥{{ item.price }}
                         </view>
                         <view>
-                          <wd-input-number />
+                          <wd-input-number v-model="item.num" :max="item.prodCount" :min="1" />
                         </view>
                       </view>
                     </view>
                   </view>
-                </wd-checkbox>
+                </view>
                 <view class="mt20rpx h2rpx w-full bg-#F0F0F0" />
-              </view>
+              </template>
             </wd-checkbox-group>
           </CollapsePanel>
         </view>

+ 12 - 11
src/subPack-xsb/commonTab/components/classfiy.vue

@@ -115,13 +115,15 @@ async function getProductList() {
   if (!isTopLoading.value) {
     goodsInTo.value = null
     nextTick(() => {
-      goodsInTo.value = res.data.length ? res.data[0].prodId : null
+      goodsInTo.value = res.data.length > 3 ? res.data[0].prodId : null
     })
   }
   else {
     goodsInTo.value = null
+
     nextTick(() => {
-      goodsInTo.value = res.data.length ? res.data[res.data.length - 4].prodId : null
+      goodsInTo.value = res.data.length > 4 ? res.data[res.data.length - 4].prodId : null
+      console.log(goodsInTo.value, 'goodsInTo.value=============')
     })
   }
   goodsLoading.value = 'finished'
@@ -447,7 +449,7 @@ function handlePay() {
           <view v-if="item.code == leftActive" class="absolute left-0 top-20rpx h60rpx w8rpx rounded-4rpx bg-[var(--them-color)]" />
         </view>
       </scroll-view>
-      <view class="content relative">
+      <view class="content">
         <view class="p20rpx">
           <image :src="`${StaticUrl}/class.png`" class="h144rpx w-full" @click="useGlobalToast().show('敬请期待 !')" />
           <view class="my20rpx flex items-center justify-end rounded-16rpx bg-#F6F6F6 px20rpx py8rpx">
@@ -458,10 +460,11 @@ function handlePay() {
           </view>
         </view>
         <scroll-view
-          :lower-threshold="10"
+          :lower-threshold="100"
           :refresher-triggered="isTopLoading" :scroll-top="scrollTop"
           :style="{ height: `calc(100vh - ${navHeight} - 700rpx)` }" enable-passive scroll-y scroll-anchoring refresher-enabled :throttle="false"
           :scroll-into-view="`class${goodsInTo}`"
+          class="relative"
           @refresherrefresh="handleSrollTop"
           @scrolltolower="handlScrollBottom"
         >
@@ -535,15 +538,13 @@ function handlePay() {
                 </view>
               </view>
             </view>
-            <!-- <wd-loadmore :state="goodsLoading" :loading-props="{ color: '#9ED605', size: 20 }" /> -->
           </view>
-
           <wd-status-tip v-else image="content" tip="暂无内容" />
-          <view v-if="!productList.length" class="h-50vh" />
+          <view v-if="goodsLoading == 'finished' || isTopLoading" class="h-30vh" />
+          <view v-if="goodsLoading == 'loading' || isTopLoading" class="absolute left-0 top-0 z-10 h-full w-full flex items-center justify-center bg-white">
+            <wd-loading color="#9ED605" :size="20" />
+          </view>
         </scroll-view>
-        <view v-if="goodsLoading == 'loading' || isTopLoading" class="absolute left-0 top-0 z-10 h-full w-full flex items-center justify-center bg-[rgba(255,255,255,.6)]">
-          <wd-loading color="#9ED605" :size="20" />
-        </view>
       </view>
     </view>
     <view
@@ -643,7 +644,7 @@ function handlePay() {
       <template #footer>
         <view class="box-border w-full flex items-center justify-between py20rpx">
           <view class="w-48%">
-            <wd-button plain hairline block @click="selectGoods = false">
+            <wd-button hairline plain block @click="selectGoods = false">
               取消
             </wd-button>
           </view>

+ 6 - 6
src/subPack-xsb/confirmOrder/index.vue

@@ -71,16 +71,16 @@ async function handlePay() {
     totalProduct.value = null
     if (res.payType !== 1) {
       await getWxCommonPayment(res)
-      paySuccess()
+      await paySuccess()
+      isPay.value = false
     }
     else {
-      paySuccess()
+      await paySuccess()
+      isPay.value = false
     }
-
-    isPay.value = false
   }
   catch {
-    payError()
+    await payError()
     isPay.value = false
   }
 }
@@ -206,7 +206,7 @@ async function handlePay() {
           </view>
         </view>
         <view class="w180rpx">
-          <wd-button size="large" :loading="isPay" @click="handlePay">
+          <wd-button size="large" :loading="isPay" :disabled="isPay" @click="handlePay">
             立即支付
           </wd-button>
         </view>

+ 2 - 2
src/subPack-xsb/goods/index.vue

@@ -377,12 +377,12 @@ async function handleAddCart() {
         <template #footer>
           <view class="box-border w-full flex items-center justify-between py20rpx">
             <view class="w-48%">
-              <wd-button plain hairline block :loading="isLoging" @click="handleAddCart">
+              <wd-button plain hairline block :loading="isLoging" :disabled="isLoging" @click="handleAddCart">
                 加入购物车
               </wd-button>
             </view>
             <view class="w-48%">
-              <wd-button block :loading="isLoging" @click="handleConfimOrder">
+              <wd-button block :loading="isLoging" :disabled="isLoging" @click="handleConfimOrder">
                 立即购买
               </wd-button>
             </view>

+ 16 - 2
src/subPack-xsb/order/index.vue

@@ -76,6 +76,13 @@ async function handleSubmitOrder(order: Api.xsbOrderList) {
   await handleCommonOrderReceive(order)
   reload()
 }
+function handleAfterSale(item: Api.xsbOrderList) {
+  if (!item.orderItemList) {
+    useGlobalToast().show('商品异常!')
+    return
+  }
+  router.push({ name: 'common-afterSales', params: { order: JSON.stringify(item.orderItemList) } })
+}
 </script>
 
 <template>
@@ -174,8 +181,8 @@ async function handleSubmitOrder(order: Api.xsbOrderList) {
               </wd-button>
             </view>
           </template>
-          <template v-if="item.hbOrderStatus === OrderStatus.OrderCancel">
-            <view>
+          <template v-if="[OrderStatus.OrderCancel, OrderStatus.OrderCompleted].includes(item.hbOrderStatus) ">
+            <view class="mr20rpx">
               <wd-button size="small" plain type="info" @click.stop="handleDel(item)">
                 删除订单
               </wd-button>
@@ -193,6 +200,13 @@ async function handleSubmitOrder(order: Api.xsbOrderList) {
               </wd-button>
             </view>
           </template>
+          <template v-if="[OrderStatus.OrderCompleted, OrderStatus.OrderWaitDelivery, OrderStatus.OrderAccepted].includes(item.hbOrderStatus) ">
+            <view>
+              <wd-button size="small" plain type="info" @click.stop="handleAfterSale(item)">
+                申请售后
+              </wd-button>
+            </view>
+          </template>
         </view>
       </view>
     </view>

+ 17 - 10
src/subPack-xsb/search/index.vue

@@ -150,17 +150,24 @@ function handleSearchText(text: string) {
       </view>
     </view>
     <view v-if="isSearch" class="px24rpx pt20rpx">
-      <view v-for="item in data" :key="item.id" class="mb20rpx box-border flex items-center justify-between rounded-16rpx bg-white p24rpx" @click="router.push({ name: 'xsb-goods', params: { id: String(item.prodId) } })">
-        <image
-          :src="item.pic"
-          class="h200rpx w200rpx flex-shrink-0 rounded-16rpx"
-        />
-        <view class="ml20rpx flex-1">
-          <view class="text-32rpx font-semibold">
-            {{ item.prodName }}
+      <view v-for="item in data" :key="item.id" class="relative mb20rpx rounded-16rpx bg-white p24rpx">
+        <view class="box-border flex items-center justify-between" @click="router.push({ name: 'xsb-goods', params: { id: String(item.prodId) } })">
+          <image
+            :src="item.pic"
+            class="h200rpx w200rpx flex-shrink-0 rounded-16rpx"
+          />
+          <view class="ml20rpx flex-1">
+            <view class="text-32rpx font-semibold">
+              {{ item.prodName }}
+            </view>
+            <view class="mt14rpx text-36rpx text-#FF4A39 font-semibold">
+              ¥{{ item.channelProdPrice }}
+            </view>
           </view>
-          <view class="mt14rpx text-36rpx text-#FF4A39 font-semibold">
-            ¥{{ item.channelProdPrice }}
+        </view>
+        <view v-if="!item.spuStock" class="absolute left-0 top-0 z10 h-full w-full flex items-center justify-center bg-[rgba(255,255,255,0.6)]">
+          <view class="flex items-center justify-center rounded-16rpx bg-[rgba(0,0,0,.6)] p8rpx text-28rpx text-white">
+            商品已售罄
           </view>
         </view>
       </view>

+ 18 - 8
src/subPack-xsb/utils/confirm-order.ts

@@ -100,20 +100,30 @@ export function getWxCommonPayment(orderPay: wxpay) {
  * 支付成功统一跳转
  */
 export function paySuccess() {
-  const { paySuccessPath, payBackIndexPath } = storeToRefs(useSysStore())
-  paySuccessPath.value = 'xsb-order'
-  payBackIndexPath.value = 'subPack-xsb/commonTab/index'
-  router.replace({ name: 'common-paySuccess' })
+  return new Promise((resolve) => {
+    const { paySuccessPath, payBackIndexPath } = storeToRefs(useSysStore())
+    paySuccessPath.value = 'xsb-order'
+    payBackIndexPath.value = 'subPack-xsb/commonTab/index'
+    router.replace({ name: 'common-paySuccess' })
+    setTimeout(() => {
+      resolve(1)
+    }, 2000)
+  })
 }
 /**
  * 星闪豹
  * 支付成功统一跳转
  */
 export function payError() {
-  const { paySuccessPath, payBackIndexPath } = storeToRefs(useSysStore())
-  paySuccessPath.value = 'xsb-order'
-  payBackIndexPath.value = 'subPack-xsb/commonTab/index'
-  router.replace({ name: 'common-payError' })
+  return new Promise((resolve) => {
+    const { paySuccessPath, payBackIndexPath } = storeToRefs(useSysStore())
+    paySuccessPath.value = 'xsb-order'
+    payBackIndexPath.value = 'subPack-xsb/commonTab/index'
+    router.replace({ name: 'common-payError' })
+    setTimeout(() => {
+      resolve(1)
+    }, 2000)
+  })
 }
 
 /**