consume.vue 7.19 KB
<template>
  <view class="page-shell booking-consume-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="goBack">‹</view>
        <view class="subpage-title-wrap">
          <text class="subpage-title">{{ consumePageTitle }}</text>
          <text class="subpage-subtitle">{{ consumePageSubtitle }}</text>
        </view>
      </view>

      <view class="subpage-hero glass-card">
        <text class="hero-kicker">{{ consumeStatus }}</text>
        <text class="hero-title">{{ booking.store }}</text>
        <text class="hero-desc">{{ booking.date }} · {{ booking.displayTime || booking.time }}</text>
      </view>

      <view class="subpage-card">
        <view class="section-head">
          <text class="section-title">确认流程</text>
          <text class="section-link">到店安排</text>
        </view>
        <view class="flow-list">
          <view v-for="(item, index) in flowSteps" :key="item.title" class="flow-item">
            <view class="flow-mark" :class="{ active: item.active, pending: !item.active }">{{ index + 1 }}</view>
            <view class="flow-copy">
              <text class="flow-title">{{ item.title }}</text>
              <text class="flow-desc">{{ item.desc }}</text>
            </view>
          </view>
        </view>
      </view>

      <view class="subpage-card">
        <view class="info-list">
          <view class="info-row">
            <text class="info-label">预约编号</text>
            <text class="info-value">LQBK{{ booking.id || 'TEMP' }}</text>
          </view>
          <view class="info-row">
            <text class="info-label">电话确认</text>
            <text class="info-value">{{ booking.confirmState || '门店稍后联系' }}</text>
          </view>
          <view class="info-row">
            <text class="info-label">护理品项</text>
            <text class="info-value">{{ itemText }}</text>
          </view>
          <view class="info-row">
            <text class="info-label">护理房间</text>
            <text class="info-value">{{ consume ? consume.room : '到店确认' }}</text>
          </view>
          <view class="info-row">
            <text class="info-label">健康师</text>
            <text class="info-value">{{ consume ? consume.therapist : '电话确认后安排' }}</text>
          </view>
        </view>
      </view>

      <view class="subpage-card">
        <view class="soft-panel">
          <text class="panel-title">门店说明</text>
          <text class="panel-desc">{{ noteText }}</text>
          <text class="panel-desc sub">{{ onsiteText }}</text>
        </view>
      </view>

      <view class="cta-row">
        <view class="secondary-button" @tap="goRecord">查看预约</view>
        <view class="primary-button" @tap="contactStore">联系门店</view>
      </view>
    </view>
  </view>
</template>

<script>
import { findRecordById, findConsumeByRecordId } from '@/data/mock'

export default {
  data() {
    return {
      booking: {
        id: 'TEMP',
        store: '绿纤大源店',
        date: '今天 03/19',
        time: '14:00',
        displayTime: '14:00 到店',
        confirmState: '门店稍后电话联系'
      },
      consume: null
    }
  },
  computed: {
    consumePageTitle() {
      return this.consume ? '护理安排' : '确认进度'
    },
    consumePageSubtitle() {
      return this.consume ? '电话确认后的到店安排,会在这里慢慢补充完整' : '预约已提交,门店电话确认后将生成护理安排'
    },
    consumeStatus() {
      return this.consume ? this.consume.status : '待门店联系'
    },
    itemText() {
      return this.consume && this.consume.itemList.length ? this.consume.itemList.join(' / ') : '电话确认后补充'
    },
    noteText() {
      return this.consume ? this.consume.managerNote : '预约提交后,门店会先与你电话确认,再为你补充本次到店安排。'
    },
    onsiteText() {
      return this.consume ? this.consume.onsiteConfirm : '如有房间、健康师或护理细节暂未确认,会在电话沟通或到店后再完成补充。'
    },
    flowSteps() {
      const hasConsume = !!this.consume
      return [
        { title: '提交预约', desc: '你的到店需求已经妥帖送达门店', active: true },
        { title: '门店电话联系', desc: hasConsume ? '门店已完成预约电话确认' : '门店将按预约顺序联系你确认', active: hasConsume },
        { title: '补充护理安排', desc: hasConsume ? '护理内容、房间与健康师已补充完成' : '确认后由后台创建护理安排', active: hasConsume },
        { title: '到店再做微调', desc: '部分细节可根据现场状态由门店再确认', active: true }
      ]
    }
  },
  onLoad(options) {
    if (options.recordId) {
      this.booking = findRecordById(options.recordId)
      this.consume = findConsumeByRecordId(options.recordId)
      return
    }
    this.booking = {
      id: 'TEMP',
      store: options.store ? decodeURIComponent(options.store) : this.booking.store,
      date: options.date ? decodeURIComponent(options.date) : this.booking.date,
      time: options.time ? decodeURIComponent(options.time) : this.booking.time,
      displayTime: options.time ? `${decodeURIComponent(options.time)} 到店` : this.booking.displayTime,
      confirmState: '门店稍后电话联系'
    }
  },
  methods: {
    goBack() {
      uni.navigateBack({ fail: () => uni.redirectTo({ url: '/packageBooking/record/record' }) })
    },
    goRecord() {
      if (this.booking.id && this.booking.id !== 'TEMP') {
        uni.redirectTo({ url: `/packageBooking/detail/detail?id=${this.booking.id}` })
        return
      }
      uni.redirectTo({ url: '/packageBooking/record/record' })
    },
    contactStore() {
      uni.showToast({ title: '门店会按预约顺序尽快联系你', icon: 'none' })
    }
  }
}
</script>

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

.flow-item {
  display: flex;
  align-items: flex-start;
  padding: 16rpx 0;
  animation: lfRevealUp 760ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.flow-item:nth-child(1) { animation-delay: 0.08s; }
.flow-item:nth-child(2) { animation-delay: 0.16s; }
.flow-item:nth-child(3) { animation-delay: 0.24s; }
.flow-item:nth-child(4) { animation-delay: 0.32s; }

.flow-mark {
  width: 44rpx;
  height: 44rpx;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22rpx;
  font-weight: 700;
  color: #fff;
  background: $brand-primary-deep;
  flex-shrink: 0;
  animation: lfPulseSoft 4.8s ease-in-out infinite;
}

.flow-mark.pending {
  color: $text-secondary;
  background: rgba(210, 191, 156, 0.16);
  animation: none;
}

.flow-copy {
  flex: 1;
  margin-left: 18rpx;
}

.flow-title,
.flow-desc,
.panel-title,
.panel-desc {
  display: block;
}

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

.flow-desc,
.panel-desc {
  margin-top: 8rpx;
  font-size: 24rpx;
  line-height: 1.8;
  color: $text-secondary;
}

.panel-desc.sub {
  margin-top: 14rpx;
}
</style>