<template>
  <div>
    <Poptip transfer placement="bottom" :style="{ width: '100%' }">
      <Input
        readonly
        clearable
        @on-clear="clearValue"
        :style="{ width: '100%' }"
        :value="finalValue"
        :disabled="disabled"
        icon="ios-calendar-outlin"
        placeholder="请选择日期"
        style="width: 200px"
      />
      <template #title>
        <div class="header">
          <div @click="leftClick">左</div>
          <div class="day-info">{{ dayInfo }}</div>
          <div @click="rightClick">右</div>
        </div>
      </template>
      <template #content>
        <div class="content">
          <div class="date-picker">
            <div class="week-list">
              <span v-for="(day, index) in weekList" :key="index">{{ day }}</span>
            </div>
            <div class="day-list">
              <div v-for="(day, index) in dayList">
                <div class="day-line">
                  <span
                    v-for="(day, indexx) in day"
                    @click="selectDay(index, indexx)"
                    :class="[
                      day.isNowMoth ? 'isNowMoth' : '',
                      day.isSelected ? 'isSelected' : '',
                      day.isNowDay ? 'isNowDay' : '',
                      day.weekday === 0 ? 'weekend' : 'weekday',
                      day.disabled ? 'disabled' : '',
                    ]"
                    >{{ day.value }}</span
                  >
                </div>
              </div>
            </div>
          </div>
          <div class="time-picker">
            <div
              :class="['time-item', item.isSelect ? 'select-item' : '', item.disabled ? 'disabled-item' : '']"
              v-for="(item, index) in timeList"
              :key="index"
              @click="selectTime(index)"
            >
              {{ item.text }}
            </div>
          </div>
        </div>
      </template>
    </Poptip>
  </div>
</template>

<script>
import moment from 'moment';
export default {
  model: {
    prop: 'value',
    event: 'change',
  },
  props: {
    disabled: {
      type: Boolean,
      default: false,
    },
    value: {
      type: [String, Number, Array],
      default: '',
    },
  },
  data() {
    return {
      finalSelect_day: '',
      dayInfo: moment(new Date()).format('YYYY-MM'),
      weekList: ['日', '一', '二', '三', '四', '五', '六'],
      dayList: [
        [1, 2, 3, 4, 5, 6, 7],
        [8, 9, 10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19, 20, 21],
        [22, 23, 24, 25, 26, 27, 28],
        [29, 30, 31, 1, 2, 3, 4],
        [5, 6, 7, 8, 9, 10, 11],
      ],
      timeList: [
        {
          text: '8:00之前',
          value: '0:00-8:00',
          startTime: 0,
          endTime: 8,
          isSelect: false,
        },
        {
          text: '8:00-12:00',
          value: '8:00-12:00',
          startTime: 8,
          endTime: 12,
          isSelect: false,
        },
        {
          text: '12:00-16:00',
          value: '12:00-16:00',
          startTime: 12,
          endTime: 16,
          isSelect: false,
        },
        {
          text: '16:00-20:00',
          value: '16:00-20:00',
          startTime: 16,
          endTime: 20,
          isSelect: false,
        },
        {
          text: '20:00之后',
          value: '20:00-24:00',
          startTime: 20,
          endTime: 24,
          isSelect: false,
        },
      ],
    };
  },
  computed: {
    finalValue() {
      const { finalSelect_day } = this;
      const selectTime = this.timeList.find((item) => item.isSelect);
      if (finalSelect_day && selectTime) {
        const startT = moment(finalSelect_day)
          .hour(selectTime.startTime)
          .minute(0)
          .second(0)
          .format(selectTime.disabled ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss');
        const endT = moment(finalSelect_day)
          .hour(selectTime.endTime)
          .minute(0)
          .second(0)
          .format(selectTime.disabled ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss');
        if (selectTime.disabled) {
          this.timeList.forEach((item) => {
            item.isSelect = false;
          });
          this.$emit('change', [startT, endT]);
          return `${finalSelect_day}`;
        } else {
          this.$emit('change', [startT, endT]);
          return `${finalSelect_day} ${selectTime.value}`;
        }
      } else {
        if (this.value && this.value.length > 0) {
          return this.finalSelect_day;
        } else {
          return '';
        }
      }
    },
  },
  mounted() {
    // 计算当前月份下的日期列表
    if (this.value && this.value.length > 0 && this.value[0]) {
      this.finalSelect_day = moment(new Date(this.value[0])).format('YYYY-MM-D');
      const startH = moment(new Date(this.value[0])).hour();
      const endH = moment(new Date(this.value[1])).hour();
      this.timeList.forEach((item) => {
        if (startH == item.startTime && endH == item.endTime) {
          item.isSelect = true;
        } else {
          item.isSelect = false;
        }
      });
      this.setDayList(this.finalSelect_day);
    } else {
      this.setDayList(new Date());
    }
  },
  methods: {
    setDayList(nday) {
      // 获取当前月份的所有天数
      const daysInMonth = moment(nday).daysInMonth();
      const dayList = [];
      for (let i = 1; i <= daysInMonth; i++) {
        // year-month-day
        dayList.push(moment(nday).format('YYYY-MM-') + i);
      }
      // 计算每一天是周几
      dayList.forEach((day, index) => {
        const weekday = moment(day).weekday();
        dayList[index] = {
          day: moment(day).format('YYYY-MM-D'),
          value: moment(day).format('D'),
          isNowMoth: true,
          isNowDay: moment(day).isSame(new Date(), 'day'),
          isSelected: moment(this.finalSelect_day).isSame(day, 'day'),
          weekday: weekday,
        };
      });
      const newList = [];
      dayList.forEach((day, index) => {
        if (index === 0 && day.weekday != 0) {
          const endIndex = dayList.findIndex((item) => item.weekday === 6);
          newList.push(dayList.slice(index, endIndex + 1));
        }
        // 以周日开始 切割成二维数组
        if (day.weekday === 0) {
          newList.push(dayList.slice(index, index + 7));
        }
      });

      if (newList[0].length !== 7) {
        let endIndex = 7 - newList[0].length;
        let startTime = newList[0][0].day;
        for (let i = 0; i < endIndex; i++) {
          newList[0].unshift({
            day: moment(startTime)
              .subtract(i + 1, 'days')
              .format('YYYY-MM-D'),
            value: moment(startTime)
              .subtract(i + 1, 'days')
              .format('D'),
            weekdays: moment(startTime)
              .subtract(i + 1, 'days')
              .weekday(),
          });
        }
      }
      if (newList[newList.length - 1].length !== 7) {
        let endIndex = 7 - newList[newList.length - 1].length;
        let startTime = newList[newList.length - 1][newList[newList.length - 1].length - 1].day;
        for (let i = 0; i < endIndex; i++) {
          newList[newList.length - 1].push({
            day: moment(startTime)
              .add(i + 1, 'days')
              .format('YYYY-MM-D'),
            value: moment(startTime)
              .add(i + 1, 'days')
              .format('D'),
            weekdays: moment(startTime)
              .add(i + 1, 'days')
              .weekday(),
          });
        }
      }
      if (newList.length !== 6) {
        const emptyList = [];
        let startTime = newList[newList.length - 1][newList[newList.length - 1].length - 1].day;
        for (let i = 0; i < 7; i++) {
          emptyList.push({
            day: moment(startTime)
              .add(i + 1, 'days')
              .format('YYYY-MM-D'),
            value: moment(startTime)
              .add(i + 1, 'days')
              .format('D'),
            weekdays: moment(startTime)
              .add(i + 1, 'days')
              .weekday(),
          });
        }
        newList.push(emptyList);
      }
      // 今天之前的日期不可选择
      newList.forEach((item, index) => {
        item.forEach((day) => {
          if (moment(day.day).isBefore(moment(), 'day')) {
            day.disabled = true;
          }
        });
      });

      this.dayList = newList;
    },
    leftClick() {
      const nday = moment(this.dayInfo).subtract(1, 'M');
      this.setDayList(nday);
      this.dayInfo = nday.format('YYYY-MM');
    },
    rightClick() {
      const nday = moment(this.dayInfo).add(1, 'M');
      this.setDayList(nday);
      this.dayInfo = nday.format('YYYY-MM');
    },
    selectDay(index1, index2) {
      const select = moment(this.dayList[index1][index2].day);
      if (this.dayList[index1][index2].disabled) {
        return;
      }
      this.finalSelect_day = moment(select).format('YYYY-MM-D');
      // 重置isSelect
      this.dayList.forEach((item) => {
        item.forEach((day) => {
          day.isSelected = false;
          day.isNowDay = false;
        });
      });
      if (!this.dayList[index1][index2].isNowMoth) {
        this.setDayList(select);
        this.dayInfo = select.format('YYYY-MM');
      } else {
        this.dayList[index1][index2].isSelected = true;
      }
      // 过滤时间段
      this.timeList.forEach((item) => {
        if (!moment(select).isSame(new Date(), 'day') || moment(new Date()).hour() < item.endTime) {
          item.disabled = false;
        } else {
          item.disabled = true;
        }
      });

      this.dayList = [...this.dayList];
    },
    selectTime(index) {
      if (this.timeList[index].disabled) {
        return;
      }
      this.timeList.forEach((item) => {
        item.isSelect = false;
      });
      this.timeList[index].isSelect = true;
      this.timeList = [...this.timeList];
    },
    clearValue() {
      this.finalSelect_day = '';
      this.timeList.forEach((item) => {
        item.isSelect = false;
      });
      this.setDayList(new Date());
      this.dayInfo = moment(new Date()).format('YYYY-MM');
      this.$emit('change', []);
    },
  },
};
</script>

<style lang="less" scoped>
/deep/.ivu-poptip-title {
  padding: 0 !important;
}
/deep/.ivu-poptip-body {
  padding: 0 !important;
}
/deep/ .ivu-poptip-arrow {
  display: none !important;
}
/deep/ .ivu-poptip-arrow::after {
  display: none !important;
}
/deep/ .ivu-poptip-rel {
  width: 100%;
}
.header {
  width: 280px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 10px;
  .day-info {
    font-size: 15px;
  }
}

.content {
  display: flex;
  justify-content: space-between;
  align-items: top;
  width: 280px;
  padding: 5px 0px;
  padding-left: 10px;

  .date-picker {
    width: 210px;
    .week-list {
      span {
        display: inline-block;
        text-align: center;
        width: 100%;

        padding: 3px;
        font-size: 15px;
      }
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    .day-list {
      .day-line {
        display: flex;
        justify-content: space-between;
        align-items: center;
        span {
          cursor: pointer;
          display: inline-block;
          width: 100%;
          text-align: center;
          padding: 3px;
          font-size: 15px;
          color: #ccc;
        }
        .isNowMoth {
          color: #595959;
        }
        .isSelected {
          background: #2d8cf0;
          color: #fff;
          border-radius: 3px;
        }
        .isNowDay {
          border: 1px solid #2d8cf0;
          border-radius: 3px;
        }
        .disabled {
          color: #ccc;
        }
      }
    }
  }
  .time-picker {
    width: 90px;
    margin-left: 10px;
    text-align: center;
    border-left: 1px solid #ececec;

    .time-item {
      height: 40px;
      line-height: 40px;
      border-bottom: 1px solid #ececec;
      cursor: pointer;
    }
    .select-item {
      background: #409eff;
      color: #fff;
    }
    .disabled-item {
      color: #ccc;
    }
  }
}
.footer {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  width: 100%;
  padding: 8px 10px;
}
</style>

image.png

最后修改:2024 年 09 月 26 日
如果觉得我的文章对你有用,请随意赞赏