payment-success.vue 5.76 KB
<template>
  <view class="page-shell payment-success-page">
    <view class="page-blur"></view>
    <view class="page-blur-secondary"></view>
    <view class="page-blur-tertiary"></view>

    <view class="page-content subpage-content">
      <view class="subpage-nav">
        <view class="subpage-back" @tap="goMall">‹</view>
        <view class="subpage-title-wrap">
          <text class="subpage-title">下单成功</text>
          <text class="subpage-subtitle">核销二维码已准备好,支持任意时间任意门店核销自提</text>
        </view>
      </view>

      <view class="subpage-hero glass-card success-hero">
        <view class="success-mark">
          <view class="success-mark-ring"></view>
          <text class="success-mark-check">✓</text>
        </view>
        <text class="hero-kicker">PICKUP READY</text>
        <text class="hero-title">你的门店取件码已经生成</text>
        <text class="hero-desc">订单编号 {{ order.orderNo }} · {{ statusText }}</text>
      </view>

      <lf-pickup-code
        v-if="order.pickupCode"
        :code="order.pickupCode"
        title="门店自提取件码"
        desc="到自提门店出示取件码,门店核销后即可完成自提。"
      />

      <view class="subpage-card">
        <view class="info-list">
          <view class="info-row">
            <text class="info-label">商品名称</text>
            <text class="info-value">{{ mainItemName }}</text>
          </view>
          <view class="info-row">
            <text class="info-label">商品数量</text>
            <text class="info-value">{{ totalQuantity }} 件</text>
          </view>
          <view class="info-row">
            <text class="info-label">自提门店</text>
            <text class="info-value">{{ order.storeName || '—' }}</text>
          </view>
          <view class="info-row">
            <text class="info-label">实付金额</text>
            <text class="info-value">¥{{ order.payAmount }}</text>
          </view>
        </view>
      </view>

      <view class="subpage-card">
        <view class="section-head">
          <text class="section-title">接下来怎么做</text>
          <text class="section-link">门店自提</text>
        </view>
        <view class="next-list">
          <view v-for="(item, index) in nextSteps" :key="item.title" class="next-item">
            <view class="next-index">{{ index + 1 }}</view>
            <view class="next-copy">
              <text class="next-title">{{ item.title }}</text>
              <text class="next-desc">{{ item.desc }}</text>
            </view>
          </view>
        </view>
      </view>

      <view class="cta-row">
        <view class="secondary-button" @tap="goMall">继续逛逛</view>
        <view class="primary-button" @tap="viewOrders">查看订单</view>
      </view>
    </view>
  </view>
</template>

<script>
import { getOrderDetail } from '@/api/mall'
import { ORDER_STATUS_TEXT } from '@/utils/orderStatus'

export default {
  data() {
    return {
      orderId: '',
      order: {},
      nextSteps: [
        { title: '保存取件码', desc: '订单详情页会持续展示取件码,不必担心找不到。' },
        { title: '到自提门店', desc: '前往下单时选择的自提门店,向门店出示取件码。' },
        { title: '完成自提', desc: '门店核销成功后即可当场领取商品。' }
      ]
    }
  },
  computed: {
    statusText() {
      return ORDER_STATUS_TEXT[this.order.orderStatus] || '待自提'
    },
    mainItemName() {
      const items = this.order.items || []
      if (!items.length) return '—'
      return items.length > 1 ? `${items[0].productName} 等 ${items.length} 件` : items[0].productName
    },
    totalQuantity() {
      const items = this.order.items || []
      return items.reduce((sum, it) => sum + (it.quantity || 0), 0)
    }
  },
  onLoad(options) {
    this.orderId = options.orderId
    this.loadOrder()
  },
  methods: {
    loadOrder() {
      getOrderDetail(this.orderId)
        .then((data) => {
          this.order = data || {}
        })
        .catch(() => {})
    },
    viewOrders() {
      uni.navigateTo({ url: `/packageProfile/order-detail/order-detail?id=${this.orderId}` })
    },
    goMall() {
      uni.reLaunch({ url: '/packageMall/main/main' })
    }
  }
}
</script>

<style lang="scss" scoped>
@import '@/styles/mixins.scss';
@import '@/styles/subpage.scss';

.success-hero {
  min-height: 260rpx;
  padding-right: 180rpx;
}

.success-mark {
  position: absolute;
  right: 40rpx;
  top: 34rpx;
  width: 112rpx;
  height: 112rpx;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.7);
  box-shadow: 0 18rpx 40rpx rgba(54, 77, 64, 0.08);
}

.success-mark-ring {
  position: absolute;
  inset: 10rpx;
  border-radius: 50%;
  border: 2rpx solid rgba(100, 140, 118, 0.2);
  animation: lfPulseSoft 4.8s ease-in-out infinite;
}

.success-mark-check {
  position: relative;
  z-index: 2;
  font-size: 42rpx;
  font-weight: 700;
  color: $brand-primary-deep;
}

.next-item {
  display: flex;
  align-items: flex-start;
  padding: 18rpx 0;
  border-bottom: 1rpx solid rgba(100, 140, 118, 0.08);
}

.next-item:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.next-index {
  width: 52rpx;
  height: 52rpx;
  margin-right: 18rpx;
  flex-shrink: 0;
  border-radius: 18rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24rpx;
  font-weight: 700;
  color: $brand-primary-deep;
  background: rgba(210, 191, 156, 0.14);
}

.next-copy {
  flex: 1;
}

.next-title,
.next-desc {
  display: block;
}

.next-title {
  font-size: 28rpx;
  font-weight: 600;
  color: $text-primary;
}

.next-desc {
  margin-top: 10rpx;
  font-size: 23rpx;
  line-height: 1.8;
  color: $text-secondary;
}
</style>