booking.vue 9.81 KB
<!--
 * @Date: 2024-01-15 13:35:51
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2024-01-16 15:15:07
 * @FilePath: /xysBooking/src/views/booking.vue
 * @Description: 预约页面
 * @Version: 1.0.0
-->
<template>
  <div class="booking-page">
    <div class="calendar">
      <div class="choose-date">
        <div class="title">
          <div class="text">选择参访日期</div>
          <div @click="chooseDate" class="day">{{ currentDateText }} 月</div>
        </div>
        <div class="days-of-week">
          <div v-for="day in daysOfWeek" :key="day" class="item">{{ day }}</div>
        </div>
        <div v-for="(week, index) in weeks" :key="index" class="weeks">
          <div v-for="date in week" :key="date"
            @click="chooseDay(date)"
            :class="['item', checked_day === findDatesInfo(date).date ? 'checked' : '',  !findDatesInfo(date).num ? 'disabled' : '']"
          >
            <p class="day-text">{{ findDatesInfo(date).text }}</p>
            <p v-if="findDatesInfo(date).num" class="day-price">¥{{ findDatesInfo(date).price }}</p>
            <p v-else class="day-no-booking">已约满</p>
          </div>
        </div>
      </div>
      <div v-if="checked_day" class="choose-time">
        <div class="title">
          <div class="text">选择参访时间段</div>
        </div>
        <div class="time-list">
          <div
            @click="chooseTime(item, index)"
            v-for="(item, index) in timePeriod"
            :key="index"
            :class="['time', !item.num ? 'disabled' : '']"
          >
            <div class="left">
              <van-icon v-if="checked_time !== index" name="https://cdn.ipadbiz.cn/xys/booking/%E5%8D%95%E9%80%8901@2x.png" />&nbsp;
              <van-icon v-else name="https://cdn.ipadbiz.cn/xys/booking/%E5%8D%95%E9%80%8902@2x.png" />&nbsp;
              {{ item.left }}
            </div>
            <div class="right">
              <span v-if="item.num">余量:{{ item.right }}</span>
              <span v-else>已约满</span>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div style="height: 5rem;"></div>
    <div class="next">
      <div @click="nextBtn" class="button" style="background-color: #A67939;">下一步</div>
    </div>

    <van-popup v-model:show="showPicker" position="bottom">
      <van-date-picker
        v-model="currentDate"
        title="选择年月"
        :min-date="minDate"
        :max-date="maxDate"
        :columns-type="columnsType"
        @confirm="onConfirm"
        @cancel="onCancel"
      />
    </van-popup>

    <van-toast v-model:show="show_error" style="">
      <template #message>
        {{ error_message }}
      </template>
    </van-toast>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { showSuccessToast, showFailToast, showToast } from 'vant';
import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'
import { useGo } from '@/hooks/useGo'

const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);

const go = useGo();

const dates_list = ref([{
  date: "2024-01-01",
  price: 5,
  num: 0,
}, {
  date: "2024-01-02",
  price: 5,
  num: 0,
}, {
  date: "2024-01-03",
  price: 5,
  num: 1,
}, {
  date: "2024-01-04",
  price: 5,
  num: 1,
}, {
  date: "2024-01-05",
  price: 5,
  num: 1,
}, {
  date: "2024-01-06",
  price: 5,
  num: 1,
}, {
  date: "2024-01-07",
  price: 5,
  num: 1,
}, {
  date: "2024-01-08",
  price: 5,
  num: 1,
}, {
  date: "2024-01-09",
  price: 5,
  num: 1,
}]);
const dates = ref(dates_list.value.map(item => item.date));

const findDatesInfo = (date) => {
  const result = dates_list.value.find((item) => item.date === date);
  const currentDate = new Date(date);
  return {
    text: currentDate.getDate().toString().padStart(2, '0'),
    date: result.date,
    price: result.price,
    num: result.num,
  };
};

const daysOfWeek = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];

const weeks = computed(() => {
  const result = [];
  let currentWeek = [];
  let currentDate = new Date(dates.value[0]);

  // 确定第一个日期是星期几
  const firstDayOfWeek = currentDate.getDay() === 0 ? 7 : currentDate.getDay();

  // 添加空白的日期,直到第一个日期的星期一
  for (let i = 1; i < firstDayOfWeek; i++) {
    currentWeek.push('');
  }

  // 添加日期
  for (const date of dates.value) {
    currentDate = new Date(date);
    const dayOfWeek = currentDate.getDay() === 0 ? 7 : currentDate.getDay();

    // 如果当前星期一,开始新的一行
    if (dayOfWeek === 1 && currentWeek.length > 0) {
      result.push(currentWeek);
      currentWeek = [];
    }

    // currentWeek.push(currentDate.getDate()); // 仅将日期部分作为字符串添加到当前星期数组
    currentWeek.push(date); // 仅将日期部分作为字符串添加到当前星期数组
  }

  // 添加最后一行
  if (currentWeek.length > 0) {
    result.push(currentWeek);
  }

  return result;
});

const checked_day = ref('');

const checked_time = ref(-1);
const timePeriod = ref([{
  left: '05:00-08:00',
  right: 1098,
  num: 1,
}, {
  left: '08:00-10:00',
  right: 98,
  num: 0,
}]);

const chooseTime = (item, index) => { // 选择时间段回调
  if (item.num) {
    checked_time.value = index;
  }
  console.log(item, index);
};

const checked_day_price = ref(0);

const chooseDay = (date) => { // 点击日期回调
  if (findDatesInfo(date).num) { // 有余数可约
    checked_day.value = date;
    checked_day_price.value = findDatesInfo(date).price;
  }
};

const showPicker = ref(false);
const chooseDate = () => {
  showPicker.value = true;
}

const raw_date = new Date();
const currentDate = ref([raw_date.getFullYear(), raw_date.getMonth()]);
const columnsType = ['year', 'month'];
const minDate = new Date(2024, 0, 1);
const maxDate = new Date(2030, 11, 1);
const currentDateText = ref((raw_date.getMonth() + 1).toString().padStart(2, '0'));

const onConfirm = ({ selectedValues, selectedOptions }) => { // 选择日期回调
  showPicker.value = false;
  currentDateText.value = selectedValues[1].toString();
  // 清空选择
  checked_day.value = '';
  checked_time.value = -1;
}
const onCancel = () => {
  showPicker.value = false;
}

const show_error = ref(false);
const error_message = ref('');
const nextBtn = () => {
  if (!checked_day.value || checked_time.value === -1) {
    show_error.value = true;
    error_message.value = '请选择日期和时间段';
  } else {
    go('/submit', { date: checked_day.value, time: timePeriod.value[checked_time.value]['left'], price: checked_day_price.value });
  }
}
</script>

<style lang="less" scoped>
.booking-page {
  position: relative;
  .calendar {
    padding: 1rem 0.5rem;
    .choose-date {
      border-radius: 5px;
      background-color: #FFFFFF;
      .title {
        padding: 0.5rem 0.75rem;
        display: flex;
        justify-content: space-between;
        align-items: center;
        .text {
          &::before {
            content: '';
            border: 2px solid #A67939;
            margin-right: 0.5rem;
          }
        }
        .day {
          background-color: #FFFBF3;
          border-radius: 7px;
          border: 1px solid #A67939;
          padding: 0.2rem 0.5rem;
          color: #A67939;
        }
      }
      .days-of-week {
        background-color: #EAEAEA;
        display: flex;
        padding: 0.75em 1%;
        font-size: 0.85rem;
        .item {
          width: 14.5%;
          text-align: center;
        }
      }
      .weeks {
        display: flex;
        padding: 0.5em 1%;
        .item {
          width: 11.5%;
          text-align: center;
          margin: 0 0.3rem;
          padding: 0.5rem 0;
          .day-text {
            color: #1E1E1E;
            font-weight: bold;
            font-size: 1.05rem;
          }
          .day-price {
            color: #A67939;
            font-size: 0.85rem;
          }
          &.checked {
            border: 1px solid #A67939;
            border-radius: 5px;
            background-color: #FFFBF3;
          }
          &.disabled {
            .day-text {
              color: #C7C7C7;
            }
            .day-price {
              color: #C7C7C7;
            }
            .day-no-booking {
              color: #C7C7C7;
              font-size: 0.75rem;
            }
          }
        }
      }
    }
    .choose-time {
      margin-top: 1rem;
      .title {
        padding: 0.5rem 0.75rem;
        display: flex;
        justify-content: space-between;
        align-items: center;
        .text {
          &::before {
            content: '';
            border: 2px solid #A67939;
            margin-right: 0.5rem;
          }
        }
      }
      .time-list {
        .time {
          display: flex;
          align-items: center;
          justify-content: space-between;
          background-color: #FFF;
          border-radius: 5px;
          padding: 0.85rem;
          margin: 1rem 0;
          .left {
            display: flex;
            align-items: center;
            color: #1E1E1E;
          }
          .right {
            color: #A67939;
          }
          &.disabled {
            background-color: #E0E0E0;
            .left {
              color: #C7C7C7;
            }
            .right {
              color: #C7C7C7;
            }
          }
        }
      }
    }
  }
  .next {
    position: fixed;
    bottom: 0;
    height: 5rem;
    width: 100vw;
    display: flex;
    left: 0;
    background-color: #FFF;
    align-items: center;
    justify-content: center;
    box-shadow: 0rem -0.33rem 0.25rem 0rem rgba(0,0,0,0.12);
    .button {
      color: #FFF;
      padding: 0.85rem 8rem;
      border-radius: 8px;
    }
  }
}
</style>