picker-loadtime.vue 7.11 KB
<template>
  <u-picker ref="picker" title="装货时间" :show="visible" :columns="columns" @confirm="onConfirm" @cancel="onCancel" :default-index="defaultIndex" @change="onChange" immediate-change />
</template>

<script>
import dayjs from 'dayjs';

export default {
  props: {
    visible: Boolean,
    value: String,
    range: String,
    separator: {
      type: String,
      default: ' ~ '
    }
  },
  data() {
    return {
      // 已选中的各列下标数组
      selectedIndexs: [],
      // 默认下标
      defaultIndex: [],
      // 记录初始值
      defaultValue: '',
      // 记录初始范围
      defaultRange: '',
    };
  },
  computed: {
    // 时间偏移值列表
    offsetDayList() {
      return [
        { text: '今天', value: 0 },
        { text: '明天', value: 1 },
        { text: '后天', value: 2 },
      ];
    },
    // 选中的时间偏移值
    offsetDay() {
      const matchIndex = this.selectedIndexs[0] || 0;
      const match = this.offsetDayList[matchIndex];
      return match.value;
    },
    // 时间类型列表
    typeList() {
      return [
        { text: '指定', value: 'point' },
        { text: '大约', value: 'section' },
      ];
    },
    // 选中的时间类型
    type() {
      const matchIndex = this.selectedIndexs[1] || 0;
      const match = this.typeList[matchIndex] || {};
      return match.value;
    },
    // 小时选项列表
    hourList() {
      const hours = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23];
      return hours.map(i => { return { text: `${i}时`, value: i }; });
    },
    // 选中的小时
    hour() {
      if (this.type !== 'point') return null;
      const matchIndex = this.selectedIndexs[2] || 0;
      const match = this.hourList[matchIndex] || {};
      return match.value;
    },
    // 分钟选项列表
    minuteList() {
      const minutes = [0, 15, 30, 45];
      return minutes.map(i => { return { text: `${i}分`, value: i }; });
    },
    // 选中的分钟
    minute() {
      if (this.type !== 'point') return null;
      const matchIndex = this.selectedIndexs[3] || 0;
      const match = this.minuteList[matchIndex] || {};
      return match.value;
    },
    // 时间段选项列表
    sectionList() {
      return [
        { text: '凌晨(0:00-6:00)', value: [{ hour: 0, minute: 0 }, { hour: 6, minute: 0 }] },
        { text: '上午(6:00-12:00)', value: [{ hour: 6, minute: 0 }, { hour: 12, minute: 0 }] },
        { text: '下午(12:00-18:00)', value: [{ hour: 12, minute: 0 }, { hour: 18, minute: 0 }] },
        { text: '夜间(18:00-24:00)', value: [{ hour: 18, minute: 0 }, { hour: 23, minute: 59, second: 59 }] },
      ]
    },
    // 选中的时间段
    section() {
      if (this.type !== 'section') return null;
      const matchIndex = this.selectedIndexs[2] || 0;
      const match = this.sectionList[matchIndex] || {};
      return match.value || [{}, {}];
    },
    // 提供给组件使用的选项列表格式
    columns() {
      if (this.type === 'point') {
        return [
          this.offsetDayList.map(i => i.text),
          this.typeList.map(i => i.text),
          this.hourList.map(i => i.text),
          this.minuteList.map(i => i.text),
        ];
      }
      return [
        this.offsetDayList.map(i => i.text),
        this.typeList.map(i => i.text),
        this.sectionList.map(i => i.text),
      ];
    },
  },
  mounted() {
    this.calculateDefaultIndex();
    this.defaultValue = `${this.value || ''}`;
    this.defaultRange = `${this.range || ''}`;
  },
  watch: {
    visible(val) {
      if (!val) {
        this.defaultValue = `${this.value || ''}`;
        this.defaultRange = `${this.range || ''}`;
      }
    }
  },
  methods: {
    // 计算默认选中下标
    calculateDefaultIndex() {
      if (this.range) {
        const valueDay = dayjs(this.value || undefined);
        const dayOffset = dayjs(this.value || undefined).diff(dayjs(), 'day');
        const dayOffsetIndex = (dayOffset > -1 && dayOffset < 3) ? dayOffset : 0;
        const currentSection = this.range.split(this.separator);
        const currentSectionEnd = currentSection[1];
        const currentSectionEndHour = dayjs(currentSectionEnd).hour();
        const sectionIndex = this.sectionList.findIndex(i => {
          const sectionStart = i?.value?.[0];
          const sectionEnd = i?.value?.[1];
          return currentSectionEndHour >= sectionStart.hour && currentSectionEndHour < sectionEnd.hour;
        });
        const defaultIndex = [dayOffsetIndex, 1, sectionIndex > -1 ? sectionIndex : 0];
        this.defaultIndex = defaultIndex;
        this.selectedIndexs = defaultIndex;
      } else {
        const valueDay = dayjs(this.value || undefined);
        const dayOffset = dayjs(this.value || undefined).diff(dayjs(), 'day');
        const dayOffsetIndex = (dayOffset > -1 && dayOffset < 3) ? dayOffset : 0;
        const hourIndex = this.hourList.findIndex(i => i.value === valueDay.hour());
        // 当前分钟匹配每15分钟的间隔时间点
        const minuteMatch = (parseInt(valueDay.minute() / 15) + (valueDay.minute() % 15 > 0 ? 1 : 0)) * 15;
        const minuteIndex = this.minuteList.findIndex(i => i.value === (minuteMatch > 45 ? 0 : minuteMatch));
        const defaultIndex = [dayOffsetIndex, 0, hourIndex, minuteIndex];
        this.defaultIndex = defaultIndex;
        this.selectedIndexs = defaultIndex;
      }
    },
    onConfirm() {
      const { value } = this.getValue();
      const now = dayjs();
      const valueTime = dayjs(value);
      if (valueTime <= now.add(30, 'minute')) {
        return uni.showToast({ icon: 'none', title: '请选择至少30分钟后的时间' });
      }
      this.emitValue();
      this.$emit('visible', false);
    },
    onCancel() {
      this.emitOriginValue();
      this.$emit('visible', false);
    },
    onChange(e) {
      const indexs = e.indexs || [];
      this.selectedIndexs = indexs;
      this.emitValue();
    },
    // 计算值
    getValue() {
      if (this.type === 'section') {
        const sectionStart = this.section[0] || {};
        const sectionEnd = this.section[1] || {};
        const value = dayjs().add(this.offsetDay, 'day').hour(sectionEnd.hour || 0).minute(sectionEnd.minute || 0).second(sectionEnd.second || 0).format('YYYY-MM-DD HH:mm:ss');
        const rangeStart = dayjs().add(this.offsetDay, 'day').hour(sectionStart.hour || 0).minute(sectionStart.minute || 0).second(sectionStart.second || 0).format('YYYY-MM-DD HH:mm:ss');
        const rangeEnd = value;
        const range = [rangeStart, rangeEnd].join(this.separator);
        return { value, range };
      } else if (this.type === 'point') {
        const value = dayjs().add(this.offsetDay, 'day').hour(this.hour).minute(this.minute).second(0).format('YYYY-MM-DD HH:mm:ss');
        return { value, range: '' };
      }
    },
    // 推送初始值
    emitOriginValue() {
      this.$emit('input', `${this.defaultValue || ''}`);
      this.$emit('range', `${this.defaultRange || ''}`);
    },
    // 推送值
    emitValue() {
      const { value, range } = this.getValue();
      this.$emit('input', value);
      this.$emit('range', range);
    }
  }
}
</script>