orderCard.vue 10.3 KB
<template>
  <view class="order-card-component">
    <view class="order-card-header">
      <nut-row>
        <nut-col span="16">
          <view style="font-weight: bold; font-size: 34rpx;">家庭豪华连排三室套房</view>
          <view style="color: #7D7C7C; font-size: 24rpx;">两室  宜住3人 </view>
        </nut-col>
        <nut-col span="8">
          <image mode="aspectFill" src="https://img.yzcdn.cn/vant/cat.jpeg" />
        </nut-col>
      </nut-row>
    </view>
    <view class="order-card-status">
      <nut-tag :color="STATUS_COLOR[props.data.status]">{{ STATUS_TEXT[props.data.status] }}</nut-tag>
    </view>
    <view class="order-card-price">
      <nut-row>
        <nut-col span="18">
          <view class="order-card-price-text">
            <text class="left"><nut-price :price="980" size="normal" /></text>
            <text class="right"><nut-price :price="1280" size="small" strike-through style="color: #7D7C7C;" /></text>
          </view>
        </nut-col>
        <nut-col span="6" class="order-card-price-num">
          <text>x1</text>
        </nut-col>
      </nut-row>
    </view>
    <view :class="['calendar-select-page', props.data.status === 'enable' || props.data.status === 'cancel' ? 'bg-gray' : '']">
      <nut-row gutter="10">
        <nut-col span="9">
          <view class="check-in-text">入住日期</view>
          <view class="check-in-info">2023.12.07 星期四</view>
        </nut-col>
        <nut-col span="5" class="book-days">
          <view class="book-days-text">共1晚</view>
        </nut-col>
        <nut-col span="9" style="margin-left: 10rpx;">
          <view class="check-in-text">退房日期</view>
          <view class="check-in-info">2023.12.08 星期五</view>
        </nut-col>
      </nut-row>
    </view>
    <view class="order-card-control">
      <nut-row>
        <nut-col span="6">
          <view class="order-info" @tap="showOrderInfo('id')">
            <text>入住信息</text>&nbsp;
            <IconFont v-if="show_info" name="rect-up" size="12" color="#7D7C7C"></IconFont>
            <IconFont v-else name="rect-down" size="12" color="#7D7C7C"></IconFont>
          </view>
        </nut-col>
        <!-- 待支付状态下,剩余时间归零 操作隐藏 -->
        <nut-col span="18" v-if="no_pay_show">
          <view v-if="props.data.status === 'no-pay' || props.data.status === 'apply'" class="order-control">
            <nut-button @tap="cancelOrder('id')" plain color="#6A4925" size="small">取消订单</nut-button>&nbsp;
            <nut-button v-if="props.data.status !== 'apply'" @tap="payOrder('id')" color="#6A4925" size="small">立即支付</nut-button>
          </view>
        </nut-col>
      </nut-row>
    </view>
    <!-- 待支付状态下,剩余时间归零 显示隐藏 -->
    <view v-if="no_pay_show" class="order-remain-time">
      <text>支付剩余时间</text>&nbsp;
      <text style="font-size: 23rpx; color: red;">
        {{ formatTime(remain_time) }}
      </text>
    </view>
    <view class="order-info-detail" v-if="show_info">
      <view class="order-info">
        <nut-row>
          <nut-col span="12">
            <view class="check-in-text">入住时间</view>
          </nut-col>
          <nut-col span="12">
            <view class="check-in-info">12月7日 14:00后</view>
          </nut-col>
        </nut-row>
        <nut-row>
          <nut-col span="12">
            <view class="check-out-text">退房日期</view>
          </nut-col>
          <nut-col span="12">
            <view class="check-out-info">12月8日 12:00前</view>
          </nut-col>
        </nut-row>
        <nut-row>
          <nut-col span="12">
            <view class="breakfast-text">早餐</view>
          </nut-col>
          <nut-col span="12">
            <view class="breakfast-num">3份</view>
          </nut-col>
        </nut-row>
        <view class="order-info-detail-tip">
          <view>12月7日 20:00后未入住,订单将被取消</view>
        </view>
      </view>
      <view class="order-detail">
        <nut-row class="wrapper">
          <nut-col span="6">联系人:</nut-col>
          <nut-col span="18" class="right">王二虎</nut-col>
        </nut-row>
        <nut-row class="wrapper">
          <nut-col span="6">联系电话:</nut-col>
          <nut-col span="18" class="right">18996999786</nut-col>
        </nut-row>
        <nut-row class="wrapper">
          <nut-col span="6">备注:</nut-col>
          <nut-col span="18" class="right"></nut-col>
        </nut-row>
        <nut-row class="wrapper">
          <nut-col span="6">下单时间:</nut-col>
          <nut-col span="18" class="right">2023-12-06</nut-col>
        </nut-row>
        <nut-row class="wrapper">
          <nut-col span="6">订单号:</nut-col>
          <nut-col span="18" class="right">20231206</nut-col>
        </nut-row>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue'
import Taro from '@tarojs/taro'
import { IconFont } from '@nutui/icons-vue-taro';

const STATUS_COLOR = {
  'cancel': '#CECECE',
  'no-pay': '#D5842D',
  'apply': '#6A4925',
  'enable': '#656565',
}

const STATUS_TEXT = {
  'cancel': '已取消',
  'apply': '待入住',
  'enable': '已入住',
  'no-pay': '待支付',
}

/**
 * 格式化时间
 * @param {*} seconds
 */
function formatTime(seconds) {
  const hours = Math.floor(seconds / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);
  const remainingSeconds = seconds % 60;

  let formattedTime = "";

  if (hours > 0) {
    formattedTime += hours.toString().padStart(2, "0") + ":";
  }

  if (minutes > 0 || hours > 0) {
    formattedTime += minutes.toString().padStart(2, "0") + ":";
  }

  formattedTime += remainingSeconds.toString().padStart(2, "0");

  return formattedTime;
}

const props = defineProps({
  data: {
    type: Object,
    default: {}
  }
});
const emit = defineEmits(["onPay"]);

const remain_time = ref(0); // 剩余时间秒数

const show_info = ref(false);
const showOrderInfo = (id) => {
  show_info.value = !show_info.value;
}

// 控制待支付状态下的显示
const no_pay_show = computed(() => {
  let flag = false;
  if (props.data.status === 'no-pay' && remain_time.value) { // 倒计时进行时
    flag = true;
  } else if (props.data.status === 'no-pay' && !remain_time.value) { // 倒计时结束
    flag = false;
  }
  return flag;
});

const cancelOrder = (id) => {
  Taro.showModal({
    title: '温馨提示',
    content: '是否确认取消订单?',
    success: function (res) {
      if (res.confirm) {
        console.log('用户点击确定')
      } else if (res.cancel) {
        console.log('用户点击取消')
      }
    }
  })
}

const payOrder = (id) => {
  // TODO: 把剩余支付时间发到支付组件上显示
  emit("onPay", { id, remain_time: remain_time.value });
  // visible.value = !visible.value;
  // Taro.showToast({
  //   title: '支付已超时',
  //   icon: 'error',
  //   duration: 2000
  // });
}

let timeId = null;

onMounted(() => {
  console.warn(props.data.status)
  remain_time.value = props.data.remain_time;
  // 进入页面后,开始倒计时
  timeId = setInterval(() => {
    remain_time.value ? remain_time.value -= 1 : 0;
  }, 1000);
});

onUnmounted(() => {
  timeId && clearInterval(timeId);
})
</script>

<style lang="less">
.order-card-component {
  margin: 1rem;
  margin-top: 0.5rem;
  // padding: 0.5rem 0;
  background-color: white;
  box-shadow: 0px 0px 8px 0px rgba(0,0,0,0.1);
  border: 1px solid #f9f9f9;
  border-radius: 0.5rem;
  overflow: hidden;
  .order-card-header {
    padding: 0.5rem;
    image {
      width: 100%; height: 3rem; border-radius: 10rpx;
    }
  }
  .order-card-status {
    padding: 0 0.5rem;
  }
  .order-card-price {
    padding: 0.5rem;
    .order-card-price-text {
      height: 2rem;
      display: flex;
      align-items: center;
      .left {
        color: #EB2E2E;
        font-size: 1.3rem;
        font-weight: bold;
      }
      .right {
        color: #7D7C7C;
        text-decoration: line-through;
        font-size: 0.85rem;
        margin-left: 5px;
      }
    }
    .order-card-price-num {
      text-align: right;
      text {
        font-size: 28rpx;
      }
    }
  }
  .calendar-select-page {
    margin: 0 0.5rem;
    background-color: #F6ECE1;
    border-radius: 10rpx;
    padding: 1rem 0;
    padding-left: 0.5rem;
    &.bg-gray {
      background-color: #F0F0F0;
    }
    .check-in-text {
      color: #7D7C7C; font-size: 0.8rem;
    }
    .check-in-info{
      color: #7D7C7C; font-size: 0.85rem; font-weight: bold;
    }
    .book-days {
      padding: 0 10rpx;
      .book-days-text {
        color: #7D7C7C; margin-top: 15%; font-size: 0.8rem; text-align: center; background-color: #fff; padding: 0.25rem 0; border-radius: 0.5rem;
      }
    }
  }
  .order-card-control {
    padding: 0.5rem;
    padding-bottom: 0;
    .order-info {
      display: flex; align-items: center; margin: 20rpx 0;height: 60rpx;
      text {
        font-size: 26rpx; color: #7D7C7C;
      }
    }
    .order-control {
      display: flex; align-items: center;height: 100rpx; justify-content: flex-end;
    }
  }
  .order-remain-time {
    display: flex;
    justify-content: flex-end;
    font-size: 23rpx;
    margin-bottom: 1rem;
    margin-right: 1rem;
  }
  .order-info-detail {
    .order-info {
      border-bottom: 1px dashed #979797; padding: 0.5rem;
      .check-in-text {
        color: #7D7C7C; font-size: 0.85rem;
      }
      .check-in-info {
        color: #7D7C7C; font-size: 0.85rem; text-align: right;
      }
      .check-out-text {
        color: #7D7C7C; font-size: 0.85rem; margin: 0.25rem 0;
      }
      .check-out-info {
        color: #7D7C7C; font-size: 0.85rem; text-align: right; margin: 0.25rem 0;
      }
      .breakfast-text {
        color: #7D7C7C; font-size: 0.85rem;
      }
      .breakfast-num {
        color: #7D7C7C; font-size: 0.85rem; text-align: right;
      }
      .order-info-detail-tip {
        font-size: 0.85rem; margin-top: 0.25rem;
        &::before {
          content: '*';
          color: red;
          margin: auto;
          display: inline-block;
        }
        view {
          color: #7D7C7C; margin: auto; display: inline-block;
        }
      }
    }
    .order-detail {
      padding: 0.5rem; font-size: 28rpx; color: #7D7C7C;
      .wrapper {
        margin-bottom: 10rpx;
        .right {
          text-align: right;
        }
      }
    }
  }
}
</style>