Răsfoiți Sursa

Merge remote-tracking branch 'origin/master' into zzx

zouzexu 2 zile în urmă
părinte
comite
bb57fd4e35

+ 27 - 0
src/api/api.type.d.ts

@@ -741,6 +741,33 @@ namespace Api {
      */
     djkOrderAttachInfo?: OmsDjkOrderAttach
     omsOrderOilVO?: OmsOrderOilVO
+    refundOrderList?: {
+      /**
+       * 申请时间
+       */
+      createTime?: string
+      /**
+       * 退款金额(元)
+       */
+      refundMoney?: number
+      /**
+       * 退款订单编号
+       */
+      refundNumber?: string
+      /**
+       * 退款总订单状态 0-进行中,1-已完成,2-积分退款成功微信退款失败,3-已取消,4-驳回
+       */
+      refundOrderStatus?: number
+      /**
+       * 退款状态描述
+       */
+      refundOrderStatusDesc?: string
+      /**
+       * 用户实际退款金额(元)
+       */
+      userRefundMoney?: number
+      [property: string]: any
+    }[]
 
   }
   interface OmsOrderOilVO {

+ 3 - 3
src/config/index.ts

@@ -11,7 +11,7 @@ const mapEnvVersion = {
   // develop: 'http://192.168.0.11:8080', // 王
   // develop: 'http://192.168.1.89:8080', // 田
   // develop: 'http://74949mkfh190.vicp.fun', // 付
-  // develop: 'http://47.109.84.152:8081',
+  develop: 'http://47.109.84.152:8081',
   // develop: 'https://5ed0f7cc.r9.vip.cpolar.cn',
   // develop: 'https://smqjh.api.zswlgz.com',
   /**
@@ -19,9 +19,9 @@ const mapEnvVersion = {
    */
   // trial: "http://192.168.1.166:8080/jeecg-boot",
   // trial: 'http://192.168.0.157:8080',
-  // trial: 'http://47.109.84.152:8081',
+  trial: 'http://47.109.84.152:8081',
   // trial: 'http://192.168.1.166:8080',
-  trial: 'https://smqjh.api.zswlgz.com',
+  // trial: 'https://smqjh.api.zswlgz.com',
   /**
    * 正式版
    */

+ 18 - 2
src/pages/index/index.vue

@@ -61,7 +61,7 @@ const navList = computed(() => {
     { icon: `${StaticUrl}/smqjh-vip.png`, title: '视频权益', name: 'video-rights-tabbar', show: !isOnlineAudit.value },
     { icon: `${StaticUrl}/smqjh-djk.png`, title: '大健康', name: 'djk-homeTabbar', show: true },
     { icon: `${StaticUrl}/smqjh-jiayou.png`, title: '加油', name: 'refueling-tabbar', show: true }, // refueling-tabbar
-    { icon: `${StaticUrl}/smqjh-attractions.png`, title: '景区', name: 'attractions-tabbar', show: true },
+    { icon: `${StaticUrl}/smqjh-attractions.png`, title: '景区', name: '', show: !isOnlineAudit.value },
     { icon: `${StaticUrl}/smqjh-diancan.png`, title: '大牌点餐', name: '', show: !isOnlineAudit.value },
     { icon: `${StaticUrl}/smqjh-jiudian.png`, title: '酒店民宿', name: '', show: !isOnlineAudit.value },
     { icon: `${StaticUrl}/smqjh-daijia.png`, title: '代驾', name: '', show: !isOnlineAudit.value },
@@ -90,6 +90,7 @@ function handleClick(name: string) {
     ;(wx as any).openOfficialAccountProfile({
       username: 'gh_6a682fa2ed1d',
     })
+
     return
   }
 
@@ -124,6 +125,11 @@ function handleChangeSwiper(e: UniHelper.SwiperOnChangeEvent) {
 
   currentIndex.value = e.detail.current
 }
+function handleJyBanner() {
+  wx.openOfficialAccountArticle({
+    url: 'https://mp.weixin.qq.com/s/lxpdZ6DUhgqg00AT9klu5Q',
+  })
+}
 </script>
 
 <template>
@@ -222,7 +228,7 @@ function handleChangeSwiper(e: UniHelper.SwiperOnChangeEvent) {
       </view>
 
       <view class="mt-20rpx w-full flex items-center justify-between">
-        <image :src="`${StaticUrl}/smqjh-fl.png`" class="h-346rpx w-344rpx flex-shrink-0" />
+        <image :src="`${StaticUrl}/smqjh-jy-banner.jpg`" class="h-346rpx w-344rpx flex-shrink-0 rounded-12rpx" @click="handleJyBanner" />
         <view class="flex flex-1 flex-col items-end justify-center" @click="handleGo">
           <image :src="`${StaticUrl}/smqjh-home-banner1.jpg`" class="h-180rpx w-344rpx rounded-12rpx" />
           <image :src="`${StaticUrl}/smqjh-home-banner2.jpg`" class="mt-14rpx h-152rpx w-344rpx rounded-12rpx" />
@@ -288,6 +294,16 @@ function handleChangeSwiper(e: UniHelper.SwiperOnChangeEvent) {
                       商品已售罄
                     </view>
                   </view>
+                  <view
+                    v-if="!item.skuList.some((it) => it.saleStatus)"
+                    class="absolute left-0 top-0 z-1 h-full w-full flex items-center justify-center bg-[rgba(255,255,255,0.6)]"
+                  >
+                    <view
+                      class="h-156rpx w-156rpx flex items-center justify-center rounded-full bg-[rgba(0,0,0,.6)] text-28rpx text-white"
+                    >
+                      商品不可售
+                    </view>
+                  </view>
                 </view>
               </grid-view>
             </scroll-view>

+ 6 - 6
src/pages/my/index.vue

@@ -13,10 +13,10 @@ definePage({
   },
 })
 const tabList = ref([
-  { title: '待支付', icon: `${StaticUrl}/1.png`, name: 'smqjh-order' },
-  { title: '待收货', icon: `${StaticUrl}/2.png`, name: 'smqjh-order' },
-  { title: '已完成', icon: `${StaticUrl}/6.png`, name: 'smqjh-order' },
-  { title: '退款售后', icon: `${StaticUrl}/3.png`, name: 'common-afterSalesList' },
+  { title: '待支付', icon: `${StaticUrl}/1.png`, name: 'smqjh-order', status: 'paddingPay' },
+  { title: '进行中', icon: `${StaticUrl}/2.png`, name: 'smqjh-order', status: 'ing' },
+  { title: '已完成', icon: `${StaticUrl}/6.png`, name: 'smqjh-order', status: 'completed' },
+  { title: '退款售后', icon: `${StaticUrl}/3.png`, name: 'common-afterSalesList', status: '' },
 ])
 onMounted(() => {
   useUserStore().getUserInfo()
@@ -35,8 +35,8 @@ function handleLoginOut() {
     },
   })
 }
-function handleGo(item: { name: string }) {
-  router.push({ name: item.name })
+function handleGo(item: { name: string, status: string }) {
+  router.push({ name: item.name, params: { status: item.status } })
 }
 </script>
 

+ 17 - 0
src/store/user.ts

@@ -426,5 +426,22 @@ export const useUserStore = defineStore('user', {
       }
       return textMap[order.hbOrderStatus as keyof typeof textMap] || '未知订单状态'
     },
+    async  getOrderNode(orderNumber: string) {
+      uni.showLoading({
+        mask: true,
+      })
+      return new Promise((resolve, reject) => {
+        Apis.xsb.deliveryNode({
+          data: {
+            orderNumber,
+          },
+        }).then((res) => {
+          // NodeList.value = res.data
+          resolve(res.data)
+        }).catch((err) => {
+          reject(err)
+        }).finally(() => uni.hideLoading())
+      })
+    },
   },
 })

+ 2 - 2
src/subPack-charge/components/plate/index.vue

@@ -278,7 +278,7 @@ watch(() => props.plateNumber, (newVal) => {
   </view>
 </template>
 
-<style scoped lang='less'>
+<style scoped lang='scss'>
     .plate {
         display: flex;
         justify-content: space-between;
@@ -352,7 +352,7 @@ watch(() => props.plateNumber, (newVal) => {
             padding: 0 19rpx 20rpx;
             .item {
                 display: inline-block;
-                width: calc(~"(100% - 72rpx) / 10");
+                width: calc((100% - 72rpx) / 10);
                 height: 84rpx;
                 margin-right: 8rpx;
                 margin-bottom: 8rpx;

+ 2 - 2
src/subPack-common/afterSales/index.vue

@@ -167,7 +167,7 @@ function handleChangeMoney() {
               </view>
             </view>
           </wd-radio>
-          <view class="mt24rpx">
+          <!-- <view class="mt24rpx">
             <wd-radio :value="2">
               <view>
                 <view class="text-left text-28rpx font-semibold">
@@ -178,7 +178,7 @@ function handleChangeMoney() {
                 </view>
               </view>
             </wd-radio>
-          </view>
+          </view> -->
         </wd-radio-group>
       </view>
       <view class="mt20rpx rounded-16rpx bg-white px24rpx py28rpx">

+ 1 - 5
src/subPack-common/integral/index.vue

@@ -14,7 +14,6 @@ const { data: info } = useRequest(() =>
   Apis.xsb.findUserPoints({}),
 )
 
-const type = ['充值', '下单', '退款', '过期积分', '退款过期积分']
 const { data: pointList, isLastPage, page } = usePagination((pageNum, pageSize) => Apis.xsb.findUserPointsPage({ data: { pageNum, pageSize } }), { data: resp => resp.data?.list, initialPage: 1, initialPageSize: 10, immediate: true, append: true })
 
 function handleScrollBottom() {
@@ -29,9 +28,6 @@ async function getNavList() {
   navTabTypeList.value = res.data?.list || []
 }
 getNavList()
-function getLabel(val: string) {
-  return navTabTypeList.value.find(i => i.value === val)?.name || '未知类型'
-}
 </script>
 
 <template>
@@ -77,7 +73,7 @@ function getLabel(val: string) {
       <view v-for="item, index in pointList" :key="item.pointsId" class="bg-white p-24rpx">
         <view class="flex items-center justify-between text-32rpx font-semibold">
           <view class="text-[#222]">
-            {{ (type[Number(item.pointsType) - 1] == '下单' ? getLabel(item.businessType) : type[Number(item.pointsType) - 1]) || '未知状态' }}
+            {{ item.businessTypeName || '未知状态' }}
           </view>
           <view class="text-[#FF4A39]">
             {{ item?.pointsTypeName }}{{ item?.variablePoints || 0 }}

+ 1 - 1
src/subPack-smqjh/components/charge-orderList/charge-orderList.vue

@@ -30,7 +30,7 @@ function handleItemClick(item: Api.xsbOrderList) {
 </script>
 
 <template>
-  <view class="mt-20rpx mt20rpx rounded-16rpx bg-#FFF p-24rpx" @click="handleItemClick(order)">
+  <view class="mb-20rpx rounded-16rpx bg-#FFF p-24rpx" @click="handleItemClick(order)">
     <view class="flex items-center justify-between">
       <view>
         <view class="text-28rpx font-bold">

+ 1 - 1
src/subPack-smqjh/components/film-orderList/film-orderList.vue

@@ -127,7 +127,7 @@ function handleOrder(orderNo: string) {
   background: #FFFFFF;
   border-radius: 16rpx 16rpx 16rpx 16rpx;
   padding: 24rpx;
-  margin-top: 20rpx;
+  margin-bottom: 20rpx;
 }
 
   .order-item {

+ 56 - 3
src/subPack-smqjh/components/xsb-orderList/xsb-orderList.vue

@@ -9,7 +9,9 @@ defineProps<{
 const _emit = defineEmits<{
   refresh: []
 }>()
-
+const NodeList = ref<Api.DeliveryNode[]>([])
+const showNode = ref(false)
+const plugins = requirePlugin('logisticsPlugin')
 async function handleCancel(order: Api.xsbOrderList) {
   await useUserStore().handleCommonCancelOrder?.(order)
   _emit('refresh')
@@ -46,10 +48,37 @@ async function handleAfterSale(item: Api.xsbOrderList) {
   }
   await useSysStore().getRefunOrder(item.orderNumber as string)
 }
+function handleTime(_order: Api.xsbOrderList) {
+
+}
+async function handleLogistics(_order: Api.xsbOrderList) {
+  // router.push({ name: 'xsb-logistics', params: { id: order.orderNumber } })
+  if (_order.dvyType === 3) {
+    const res = await useUserStore().getOrderNode(String(_order.orderNumber))
+    NodeList.value = res as Api.DeliveryNode[]
+    showNode.value = true
+  }
+  if ([1, 10].includes(Number(_order.dvyType)) && _order.actualTotal) {
+    uni.showLoading({ mask: true })
+    try {
+      const res = await Apis.xsb.getWaybillToken({ data: { orderNumber: String(_order.orderNumber) } })
+      uni.hideLoading()
+      const jsData = JSON.parse(res.data)
+      if (jsData.errmsg === 'ok') {
+        plugins.openWaybillTracking({
+          waybillToken: jsData.waybill_token,
+        })
+      }
+    }
+    catch {
+      uni.hideLoading()
+    }
+  }
+}
 </script>
 
 <template>
-  <view class="mt-20rpx rounded-16rpx bg-white p-24rpx">
+  <view class="mb-20rpx rounded-16rpx bg-white p-24rpx">
     <view class="flex items-center justify-between">
       <view class="flex items-center">
         <image :src="`${StaticUrl}/order-icon.png`" class="h-36rpx w-36rpx" />
@@ -140,14 +169,38 @@ async function handleAfterSale(item: Api.xsbOrderList) {
           </wd-button>
         </view>
       </template>
-      <template v-if="order.refundStatus != 2 && [OrderStatus.OrderCompleted, OrderStatus.OrderWaitDelivery, OrderStatus.OrderAccepted].includes(order.hbOrderStatus) ">
+      <template v-if="order.refundStatus != 2 && [OrderStatus.OrderCompleted, OrderStatus.OrderWaitDelivery, OrderStatus.OrderAccepted].includes(order.hbOrderStatus) && handleTime(order)">
         <view class="mr-20rpx">
           <wd-button size="small" plain type="info" @click.stop="() => handleAfterSale(order)">
             申请售后
           </wd-button>
         </view>
       </template>
+      <template v-if="[OrderStatus.OrderAccepted, OrderStatus.OrderWaitDelivery, OrderStatus.OrderDelivering].includes(order.hbOrderStatus)">
+        <view class="mr-20rpx">
+          <wd-button size="small" plain type="info" @click.stop="handleLogistics(order)">
+            查看物流
+          </wd-button>
+        </view>
+      </template>
     </view>
+    <Zpopup v-model="showNode" :showfooter="false">
+      <view class="p-24rpx">
+        <view class="text-center text-32rpx font-semibold">
+          订单追踪
+        </view>
+        <wd-steps :active="0" vertical dot>
+          <wd-step v-for="item in NodeList" :key="item.id">
+            <template #title>
+              {{ item.content }}
+            </template>
+            <template #description>
+              {{ item.createTime }}
+            </template>
+          </wd-step>
+        </wd-steps>
+      </view>
+    </Zpopup>
   </view>
 </template>
 

+ 57 - 8
src/subPack-smqjh/order/index.vue

@@ -14,6 +14,14 @@ const skelet = ref(true)
 const navActiveTab = ref('all')
 const scrollViewId = ref()
 const orderStatusActive = ref('all')
+
+const orderCache = new Map<string, Api.xsbOrderList[]>()
+
+const tabLastPageMap = new Map<string, boolean>()
+function getCacheKey() {
+  return `${navActiveTab.value}-${orderStatusActive.value}`
+}
+
 const { data: orderList, isLastPage, page, reload } = usePagination((pageNum, pageSize) => Apis.xsb.orderList({
   data: {
     businessType: unref(navActiveTab) === 'all' ? '' : unref(navActiveTab),
@@ -28,28 +36,69 @@ const { data: orderList, isLastPage, page, reload } = usePagination((pageNum, pa
   initialData: [],
   data: res => res.data?.list,
   append: true,
-}).onSuccess(() => skelet.value = false)
+}).onSuccess(() => {
+  skelet.value = false
+  const key = getCacheKey()
+  orderCache.set(key, [...orderList.value])
+  setTimeout(() => {
+    tabLastPageMap.set(key, isLastPage.value)
+  }, 100)
+})
 
+function loadTab() {
+  const key = getCacheKey()
+  if (orderCache.has(key)) {
+    orderList.value = orderCache.get(key)!
+    skelet.value = false
+    uni.pageScrollTo({ scrollTop: 0, duration: 0 })
+  }
+  else {
+    tabLastPageMap.delete(key)
+    skelet.value = true
+    orderList.value = []
+    reload()
+  }
+}
+onLoad((options: any) => {
+  if (options.status) {
+    orderStatusActive.value = options.status
+  }
+})
 function handleChangeTypeNav(value: string) {
-  skelet.value = true
   navActiveTab.value = value
   scrollViewId.value = null
-  orderList.value = []
+  orderStatusActive.value = 'all'
   nextTick(() => scrollViewId.value = value)
-  reload()
+  loadTab()
 }
+
 onShow(() => {
-  // orderList.value = []
+  // 页面重新显示:清除当前 tab 的所有状态,强制刷新
+  const key = getCacheKey()
+  orderCache.delete(key)
+  tabLastPageMap.delete(key)
   reload()
 })
+
 onReachBottom(() => {
-  if (!isLastPage.value) {
+  const key = getCacheKey()
+  // 优先使用 per-tab 的 isLastPage,避免从其他 tab 继承错误状态
+  const tabIsLast = tabLastPageMap.has(key) ? tabLastPageMap.get(key) : isLastPage.value
+  if (!tabIsLast) {
     page.value++
   }
 })
 function handleChangeStatus(value: string) {
-  skelet.value = true
   orderStatusActive.value = value
+  loadTab()
+}
+
+// 子组件触发刷新时,清除当前 tab 的所有状态再重新加载
+function handleRefresh() {
+  const key = getCacheKey()
+  orderCache.delete(key)
+  tabLastPageMap.delete(key)
+  skelet.value = true
   orderList.value = []
   reload()
 }
@@ -134,7 +183,7 @@ function handleChangeStatus(value: string) {
         <template v-for="item in orderList" :key="item.orderNumber">
           <OrderRenderer
             :order-list="item"
-            @refresh="reload"
+            @refresh="handleRefresh"
           />
         </template>
         <StatusTip v-if="!orderList.length" tip="暂无内容" />

+ 6 - 6
src/subPack-xsb/commonTab/components/my.vue

@@ -3,20 +3,20 @@ import { StaticUrl } from '@/config'
 import router from '@/router'
 
 const tabList = ref([
-  { title: '待支付', icon: `${StaticUrl}/1.png`, name: 'xsb-order' },
-  { title: '待收货', icon: `${StaticUrl}/2.png`, name: 'xsb-order' },
-  { title: '已完成', icon: `${StaticUrl}/6.png`, name: 'xsb-order' },
-  { title: '退款售后', icon: `${StaticUrl}/3.png`, name: 'common-afterSalesList' },
+  { title: '待支付', icon: `${StaticUrl}/1.png`, name: 'xsb-order', status: 'paddingPay' },
+  { title: '进行中', icon: `${StaticUrl}/2.png`, name: 'xsb-order', status: 'ing' },
+  { title: '已完成', icon: `${StaticUrl}/6.png`, name: 'xsb-order', status: 'completed' },
+  { title: '退款售后', icon: `${StaticUrl}/3.png`, name: 'common-afterSalesList', status: '' },
 ])
 
 const { token, userInfo, getUserAvatar } = storeToRefs(useUserStore())
 useUserStore().getUserInfo()
-function handleGo(item: { name: string }) {
+function handleGo(item: { name: string, status: string }) {
   // if (item.name === 'common-afterSalesList') {
   //   useGlobalToast().show('此功能暂未开放')
   //   return
   // }
-  router.push({ name: item.name })
+  router.push({ name: item.name, params: { status: item.status } })
 }
 </script>
 

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

@@ -16,7 +16,7 @@ const isPay = ref(false)
 const remarks = ref('')
 
 const offsetPoints = computed(() => {
-  const money = (Number(unref(orderInfo)?.transfee) * 100) + (Number(unref(orderInfo)?.price) * 100)
+  const money = Math.round(Number(unref(orderInfo)?.transfee) * 100) + Math.round(Number(unref(orderInfo)?.price) * 100)
   if (Number(unref(orderInfo)?.offsetPoints) > money) {
     return money
   }

+ 6 - 1
src/subPack-xsb/order/index.vue

@@ -51,6 +51,11 @@ function handleChangeStatus(value: string) {
   orderList.value = []
   reload()
 }
+onLoad((options: any) => {
+  if (options.status) {
+    orderStatusActive.value = options.status
+  }
+})
 
 onReachBottom(() => {
   if (!isLastPage.value) {
@@ -89,7 +94,7 @@ onShow(() => {
         </view>
       </view>
     </view>
-    <view class="px-24rpx">
+    <view class="px-24rpx pt-20rpx">
       <template v-for="item in orderList" :key="item.orderNumber">
         <xsbOrderList :order="item" @refresh="reload" />
       </template>

+ 28 - 20
src/subPack-xsb/orderDetaile/index.vue

@@ -22,8 +22,9 @@ const mapMarkers = ref<MapMarker[]>([])
 const mapPolyLine = ref<MapPolyline[]>([])
 const showNode = ref(false)
 const NodeList = ref<Api.DeliveryNode[]>([])
-const viewDevyBtn = computed(() => {
-  return orderInfo.value?.actualTotal && orderInfo.value.dvyType === 1
+const refundStatus = ['进行中', '已完成', '退款成功', '已取消', '已驳回']
+const viewDevyBtn = computed(() => { // 2026.3.31,后端说这个字段返回的10是最新的快递,需要兼容1,所以1和10都需要显示
+  return orderInfo.value?.actualTotal && [1, 10].includes(Number(orderInfo.value.dvyType))
 })
 const showMapStatus = [OrderStatus.OrderAccepted, OrderStatus.OrderWaitDelivery, OrderStatus.OrderDelivering, OrderStatus.OrderArrived]
 const mapStaticShopImg = {
@@ -220,28 +221,12 @@ async function getOrderMapInf() {
 
   console.log(mapPolyLine.value, 'mapPolyLine')
 }
-async function getOrderNode() {
-  uni.showLoading({
-    mask: true,
-  })
-  return new Promise((resolve, reject) => {
-    Apis.xsb.deliveryNode({
-      data: {
-        orderNumber: String(orderInfo.value?.orderNumber),
-      },
-    }).then((res) => {
-      NodeList.value = res.data
-      resolve(res.data)
-    }).catch((err) => {
-      reject(err)
-    }).finally(() => uni.hideLoading())
-  })
-}
 
 async function handleMarkerTap(e: UniHelper.MapOnMarkertapEvent) {
   console.log(e, 'sadada')
   if (orderInfo.value?.dvyType === 3) {
-    await getOrderNode()
+    const res = await useUserStore().getOrderNode(String(orderInfo.value?.orderNumber))
+    NodeList.value = res as Api.DeliveryNode[]
     showNode.value = true
   }
   if (viewDevyBtn.value) {
@@ -265,6 +250,9 @@ async function handleReceive() {
   await useUserStore().handleCommonOrderReceive(orderInfo.value as Api.xsbOrderList)
   getDetail(String(unref(orderInfo)?.orderNumber))
 }
+function handleRefundDetail(item: any) {
+  router.push({ name: 'common-afterSalesDetail', params: { refundNumber: String(item.refundNumber) } })
+}
 </script>
 
 <template>
@@ -500,6 +488,26 @@ async function handleReceive() {
           </view>
         </view>
       </view>
+
+      <view v-if="orderInfo.refundOrderList" class="mt-20rpx rounded-16rpx bg-white p-24rpx">
+        <view v-for="item in orderInfo.refundOrderList" :key="item.createTime" class="mb10rpx" @click="handleRefundDetail(item)">
+          <view class="flex items-center justify-between">
+            <view>{{ item.refundName }} </view>
+            <view class="flex items-center">
+              <view>查看详情</view>
+              <wd-icon name="arrow-right" size="22px" />
+            </view>
+          </view>
+          <view class="mt10rpx flex items-center text-24rpx text-#AAA">
+            <view>
+              {{ refundStatus[Number(item.refundOrderStatus)] }}
+            </view>
+            <view v-if="[1, 2].includes(Number(item.refundOrderStatus))" class="ml-10rpx">
+              退款金额: {{ item.refundMoney }} 元
+            </view>
+          </view>
+        </view>
+      </view>
       <view class="mt-20rpx rounded-16rpx bg-white p-24rpx">
         <view class="mb-24rpx text-28rpx font-semibold">
           订单信息