doum
2026-04-23 7d242579a0923e7639876797e738a22c45d6e2d0
app/pages/order/order.vue
@@ -1,6 +1,70 @@
<template>
   <view>
   <view class="order-page">
      <view class="order-page__nav" :style="{ paddingTop: statusBarHeight + 'px' }">
         <view class="order-page__nav-inner">
            <text class="order-page__nav-title">我的订单</text>
         </view>
      </view>
      <view class="order-page__tabs" :style="{ top: navHeight + 'px' }">
         <view v-for="tab in displayTabs" :key="tab.value" class="order-page__tab" :class="{ 'order-page__tab--active': activeTab === tab.value }" @click="activeTab = tab.value">
            <text class="order-page__tab-text">{{ tab.label }}</text>
            <view v-if="activeTab === tab.value" class="order-page__tab-line"></view>
         </view>
      </view>
      <scroll-view class="order-page__body" scroll-y :style="bodyStyle">
         <view class="order-page__list">
            <view v-for="item in currentOrders" :key="item.id" class="order-card" @click="goToOrderDetail(item)">
               <view class="order-card__head">
               <view class="order-card__head-left">
                  <image class="order-card__badge-icon" :src="getBadgeIcon(item.badge)" mode="widthFix"></image>
                  <text class="order-card__time-text">下单时间: {{ item.orderTime }}</text>
               </view>
                  <text class="order-card__status" :class="{ 'order-card__status--highlight': item.actions && item.actions.length }">{{ item.statusText }}</text>
               </view>
               <view class="order-card__route-item">
                  <view class="order-card__point order-card__point--pickup">取</view>
                  <view class="order-card__route-texts">
                     <text class="order-card__route-title">{{ item.pickupName }}</text>
                     <text class="order-card__route-desc">{{ item.pickupAddress }}</text>
                  </view>
               </view>
               <view class="order-card__route-item order-card__route-item--delivery">
                  <view class="order-card__point order-card__point--delivery">送</view>
                  <view class="order-card__route-texts">
                     <text class="order-card__route-title">{{ item.deliveryName }}</text>
                     <text class="order-card__route-desc">{{ item.deliveryAddress }}</text>
                  </view>
               </view>
               <view class="order-card__footer">
                  <view class="order-card__arrival">
                     <image class="order-card__clock" src="/static/image/ic_clock@2x.png" mode="aspectFit"></image>
                     <text class="order-card__arrival-text">{{ item.arriveLabel || '送达时间:' }}{{ item.arriveTime }}</text>
                  </view>
                  <view class="order-card__price-wrap">
                     <text v-if="item.priceTag" class="order-card__price-tag">{{ item.priceTag }}</text>
                     <text class="order-card__price">{{ item.price }}</text>
                  </view>
               </view>
               <view v-if="item.actions && item.actions.length" class="order-card__actions">
                  <button
                     v-for="action in item.actions"
                     :key="action.text"
                     class="order-card__action-btn"
                     :class="['order-card__action-btn--' + action.type, { 'order-card__action-btn--primary-fill': action.fill }]"
                     hover-class="order-card__action-btn--hover"
                  >
                     {{ action.text }}
                  </button>
               </view>
            </view>
         </view>
      </scroll-view>
   </view>
</template>
@@ -8,12 +72,461 @@
   export default {
      data() {
         return {
         };
            statusBarHeight: 0,
            navHeight: 0,
            activeTab: 'all',
            tabs: [
               { label: '全部', value: 'all' },
               { label: '待取货', value: 'pickup' },
               { label: '配送中', value: 'delivering' },
               { label: '已完成', value: 'finished' }
            ],
            orders: [
               {
                  id: 1,
                  type: 'pickup',
                  badge: '标速达',
                  badgeType: 'blue',
                  orderTime: '2026-04-12 12:09',
                  statusText: '待取货',
                  pickupName: '中铁快运南站旗舰店',
                  pickupAddress: '莲花路200号莲花产业园F栋401',
                  deliveryName: '佳苑巴黎都市3期10栋301室',
                  deliveryAddress: '洞庭湖路与湖北路交叉口西150米',
                  arriveLabel: '',
                  arriveTime: '45分钟内送达',
                  priceTag: '',
                  price: '¥20.5',
                  actions: [
                     { text: '取消订单', type: 'light', fill: false },
                     { text: '取货码', type: 'primary', fill: false },
                     { text: '拍照取货', type: 'primary', fill: true }
                  ]
               },
               {
                  id: 4,
                  type: 'pickup',
                  badge: '极速达',
                  badgeType: 'red',
                  orderTime: '2026-04-12 12:33',
                  statusText: '待取货',
                  pickupName: '中铁快运南站旗舰店',
                  pickupAddress: '莲花路200号莲花产业园F栋401',
                  deliveryName: '佳苑巴黎都市3期10栋301室',
                  deliveryAddress: '洞庭湖路与湖北路交叉口西150米',
                  arriveLabel: '',
                  arriveTime: '50分钟内送达',
                  priceTag: '',
                  price: '¥20.5',
                  actions: [
                     { text: '取消订单', type: 'light', fill: false },
                     { text: '取货码', type: 'primary', fill: false },
                     { text: '拍照取货', type: 'primary', fill: true }
                  ]
               },
               {
                  id: 2,
                  type: 'delivering',
                  badge: '极速达',
                  badgeType: 'red',
                  orderTime: '2026-04-12 12:33',
                  statusText: '配送中',
                  pickupName: '中铁快运南站旗舰店',
                  pickupAddress: '莲花路200号莲花产业园F栋401',
                  deliveryName: '佳苑巴黎都市3期10栋301室',
                  deliveryAddress: '洞庭湖路与湖北路交叉口西150米',
                  arriveLabel: '送达时间:',
                  arriveTime: '04-12 12:58',
                  priceTag: '',
                  price: '¥20.5'
               },
               {
                  id: 5,
                  type: 'rated',
                  badge: '极速达',
                  badgeType: 'red',
                  orderTime: '2026-04-12 13:08',
                  statusText: '已评价',
                  pickupName: '中铁快运南站旗舰店',
                  pickupAddress: '莲花路200号莲花产业园F栋401',
                  deliveryName: '佳苑巴黎都市3期10栋301室',
                  deliveryAddress: '洞庭湖路与湖北路交叉口西150米',
                  arriveLabel: '送达时间:',
                  arriveTime: '04-12 13:36',
                  priceTag: '',
                  price: '¥18.8'
               },
               {
                  id: 6,
                  type: 'cancelled',
                  badge: '标速达',
                  badgeType: 'blue',
                  orderTime: '2026-04-12 13:18',
                  statusText: '已取消',
                  pickupName: '中铁快运南站旗舰店',
                  pickupAddress: '莲花路200号莲花产业园F栋401',
                  deliveryName: '佳苑巴黎都市3期10栋301室',
                  deliveryAddress: '洞庭湖路与湖北路交叉口西150米',
                  arriveLabel: '送达时间:',
                  arriveTime: '04-12 13:52',
                  priceTag: '',
                  price: '¥16.5'
               },
               {
                  id: 3,
                  type: 'finished',
                  badge: '极速达',
                  badgeType: 'red',
                  orderTime: '2026-04-12 12:33',
                  statusText: '已完成',
                  pickupName: '中铁快运南站旗舰店',
                  pickupAddress: '莲花路200号莲花产业园F栋401',
                  deliveryName: '佳苑巴黎都市3期10栋301室',
                  deliveryAddress: '洞庭湖路与湖北路交叉口西150米',
                  arriveLabel: '送达时间:',
                  arriveTime: '04-12 12:58',
                  priceTag: '已结算',
                  price: '¥20.5'
               }
            ]
         }
      },
      computed: {
         displayTabs() {
            const countMap = {
               pickup: this.orders.filter((item) => item.type === 'pickup').length,
               delivering: this.orders.filter((item) => item.type === 'delivering').length,
               finished: this.orders.filter((item) => item.type === 'finished').length
            }
            return this.tabs.map((tab) => {
               if (!countMap[tab.value]) {
                  return tab
               }
               return {
                  ...tab,
                  label: `${tab.label} ${countMap[tab.value]}`
               }
            })
         },
         bodyStyle() {
            return {
               marginTop: this.navHeight + uni.upx2px(88) + 'px',
               height: `calc(100vh - ${this.navHeight + uni.upx2px(88)}px)`
            }
         },
         currentOrders() {
            if (this.activeTab === 'all') {
               return this.orders
            }
            return this.orders.filter((item) => item.type === this.activeTab)
         }
      },
      onLoad() {
         const systemInfo = uni.getSystemInfoSync()
         this.statusBarHeight = systemInfo.statusBarHeight || 0
         this.navHeight = this.statusBarHeight + uni.upx2px(88)
      },
      methods: {
         getBadgeIcon(badge) {
            const badgeMap = {
               '极速达': '/static/image/ic_jisuda@2x.png',
               '标速达': '/static/image/ic_biaosuda@2x.png'
            }
            return badgeMap[badge] || ''
         },
         goToOrderDetail(item) {
            uni.navigateTo({
               url: `/pages/order-detail/order-detail?id=${item.id}&status=${item.type === 'delivering' ? 'delivering' : item.type === 'finished' ? 'finished' : item.type === 'cancelled' ? 'cancelled' : item.type === 'rated' ? 'rated' : 'pickup'}`
            })
         }
      }
   }
</script>
<style lang="scss">
<style lang="scss" scoped>
   .order-page {
      height: 100vh;
      background: #f5f7fb;
      overflow: hidden;
</style>
      &__nav {
         position: fixed;
         left: 0;
         top: 0;
         right: 0;
         z-index: 10;
         background: linear-gradient(180deg, #1f73f6 0%, #1b6cf2 100%);
      }
      &__nav-inner {
         height: 88rpx;
         display: flex;
         align-items: center;
         padding: 0 28rpx;
      }
      &__nav-title {
         font-size: 38rpx;
         font-weight: 700;
         color: #ffffff;
      }
      &__tabs {
         position: fixed;
         left: 0;
         right: 0;
         z-index: 9;
         height: 88rpx;
         display: flex;
         align-items: center;
         background: #ffffff;
         box-shadow: 0 10rpx 20rpx rgba(40, 72, 128, 0.04);
      }
      &__tab {
         position: relative;
         flex: 1;
         height: 100%;
         display: flex;
         justify-content: center;
         align-items: center;
         &--active {
            .order-page__tab-text {
               color: #272b33;
               font-weight: 700;
            }
         }
      }
      &__tab-text {
         font-size: 30rpx;
         color: #8f96a3;
      }
      &__tab-line {
         position: absolute;
         left: 26rpx;
         right: 26rpx;
         bottom: 0;
         height: 4rpx;
         border-radius: 999rpx;
         background: #1a73f8;
      }
      &__body {
         box-sizing: border-box;
      }
      &__list {
         padding: 18rpx 22rpx calc(env(safe-area-inset-bottom) + 26rpx);
      }
   }
   .order-card {
      margin-bottom: 18rpx;
      padding: 20rpx 18rpx 18rpx;
      border-radius: 20rpx;
      background: #ffffff;
      box-shadow: 0 8rpx 20rpx rgba(43, 65, 106, 0.05);
      &__head {
         display: flex;
         justify-content: space-between;
         align-items: center;
      }
      &__head-left {
         display: flex;
         align-items: center;
         gap: 12rpx;
         min-width: 0;
      }
      &__badge {
         padding: 4rpx 10rpx;
         border-radius: 10rpx;
         font-size: 22rpx;
         line-height: 1.2;
         font-weight: 600;
         &--blue {
            border: 1rpx solid #75cfff;
            color: #27a8f8;
            background: #eefaff;
         }
         &--red {
            border: 1rpx solid #ff8f8f;
            color: #ff5d5d;
            background: #fff1f1;
         }
      }
      &__badge-icon {
         width: 108rpx;
         height: 40rpx;
         flex-shrink: 0;
      }
      &__time-text,
      &__status,
      &__route-desc,
      &__arrival-text {
         font-size: 24rpx;
         color: #a1a7b2;
      }
      &__status {
         flex-shrink: 0;
         &--highlight {
            color: #ff4a3d;
            font-weight: 700;
         }
      }
      &__route-item {
         display: flex;
         align-items: flex-start;
         margin-top: 22rpx;
         &--delivery {
            margin-top: 20rpx;
         }
      }
      &__point {
         width: 34rpx;
         height: 34rpx;
         line-height: 34rpx;
         text-align: center;
         border-radius: 50%;
         font-size: 22rpx;
         font-weight: 700;
         color: #ffffff;
         flex-shrink: 0;
         margin-right: 16rpx;
         &--pickup {
            background: #2ab8ff;
         }
         &--delivery {
            background: #ff9d2e;
         }
      }
      &__route-texts {
         flex: 1;
         min-width: 0;
      }
      &__route-title {
         display: block;
         font-size: 34rpx;
         font-weight: 700;
         color: #2d3139;
         line-height: 1.3;
      }
      &__route-desc {
         display: block;
         margin-top: 8rpx;
         line-height: 1.4;
      }
      &__footer {
         display: flex;
         justify-content: space-between;
         align-items: center;
         margin-top: 22rpx;
         padding-top: 16rpx;
         border-top: 1rpx solid #f0f2f6;
      }
      &__arrival {
         display: flex;
         align-items: center;
         gap: 10rpx;
      }
      &__clock {
         width: 24rpx;
         height: 24rpx;
         flex-shrink: 0;
      }
      &__price-wrap {
         display: flex;
         align-items: center;
         gap: 10rpx;
      }
      &__price-tag {
         padding: 3rpx 8rpx;
         border-radius: 8rpx;
         border: 1rpx solid #ff8f8f;
         font-size: 22rpx;
         font-weight: 600;
         color: #ff6a6a;
         background: #fff4f4;
      }
      &__price {
         font-size: 40rpx;
         font-weight: 700;
         color: #ff4030;
      }
      &__actions {
         display: flex;
         justify-content: flex-end;
         gap: 20rpx;
         margin-top: 18rpx;
         padding-top: 18rpx;
         border-top: 1rpx solid #f0f2f6;
      }
      &__action-btn {
         width: 160rpx;
         height: 64rpx;
         line-height: 64rpx;
         padding: 0;
         border-radius: 34rpx;
         font-size: 28rpx;
         font-weight: 500;
         border: 1rpx solid transparent;
         background: #ffffff;
         box-sizing: border-box;
         &::after {
            border: 0;
         }
         &--light {
            border-color: #d7dbe3;
            color: #8f96a3;
         }
         &--primary {
            border-color: #2c7cff;
            color: #2c7cff;
         }
         &--primary-fill {
            background: #2c7cff;
            color: #ffffff;
         }
         &--hover {
            opacity: 0.92;
         }
      }
   }
</style>