<template>
  <el-date-picker
    v-model="innerValue"
    type="datetimerange"
    range-separator="至"
    value-format="YYYY-MM-DD HH:mm:ss"
    :disabled-hours="disabledHours"
    :disabled-minutes="disabledMinutes"
    :disabled-seconds="disabledSeconds"
    :disabled-date="isLimit ? disabledDate : null"
    :start-placeholder="startPlaceholder"
    :end-placeholder="endPlaceholder"
    v-bind="$attrs"
    @calendar-change="handleCalendarChange"
  />
</template>

<script setup lang="ts">
import { ref, defineProps, watch } from 'vue';

// 定义传入的props
const props = withDefaults(
  defineProps<{
    modelValue: [Date, Date] | null;
    isLimit?: boolean; // 是否启用日期限制
    limitType?: 'before' | 'after'; // 限制类型:'before' 或 'after'
    startPlaceholder?: string;
    endPlaceholder?: string;
  }>(),
  {
    startPlaceholder: '开始日期',
    endPlaceholder: '结束日期',
    limitType: 'before',
    isLimit: false
  }
);

const emit = defineEmits<{
  (event: 'update:modelValue', value: [Date, Date] | null): void;
}>();

// 内部数据存储,使用v-model进行双向绑定
const innerValue = ref<[Date, Date] | null>(props.modelValue);

// 存储选中的时间范围
const selectedTimeRange = ref<{ start: Date | null; end: Date | null }>({
  start: new Date(),
  end: new Date()
});

// 监听 modelValue 的变化以更新 innerValue
watch(
  () => props.modelValue,
  newValue => {
    innerValue.value = newValue;
  }
);

// 监听 innerValue 的变化并向父组件发出更新事件
watch(innerValue, newValue => {
  emit('update:modelValue', newValue);
});

// 禁用日期
const disabledDate = (time: Date) => {
  if (props.limitType === 'before') {
    return time.getTime() < Date.now() - 8.64e7; // 禁用今天之前的日期
  } else if (props.limitType === 'after') {
    return time.getTime() > Date.now() - 8.64e7; // 禁用今天之后的日期
  }
  return false;
};

// 更新选择的时间范围
const handleCalendarChange = (val: [Date, Date | null]) => {
  selectedTimeRange.value = {
    start: val[0],
    end: val[1]
  };
};

// 禁用小时
const disabledHours = (type: string) => {
  if (!props.isLimit) return [];
  const now = new Date();
  if (!selectedTimeRange.value.start && !selectedTimeRange.value.end) {
    return [];
  }
  const selectedDate = type === 'start' ? selectedTimeRange.value.start : selectedTimeRange.value.end;

  if (selectedDate) {
    const selectedDay = selectedDate.getDate();
    const currentDay = now.getDate();
    // 根据 limitType 禁用小时
    if (selectedDay === currentDay) {
      if (props.limitType === 'after') {
        const end = 24;
        const start = now.getHours();
        return Array.from({ length: end - start }, (_, i) => i + start + 1);
      } else {
        return Array.from({ length: now.getHours() }, (_, i) => i);
      }
    }
  }
  return [];
};

// 禁用分钟
const disabledMinutes = (hour: number, type: string) => {
  if (!props.isLimit) return [];
  const now = new Date();
  const selectedDate = type === 'start' ? selectedTimeRange.value.start : selectedTimeRange.value.end;

  if (selectedDate) {
    const selectedDateTime = new Date(selectedDate);
    const isToday = selectedDateTime.getDate() === now.getDate();
    const isCurrentHour = hour === now.getHours();

    if (isToday && isCurrentHour) {
      if (props.limitType === 'after') {
        const end = 60;
        const start = now.getMinutes();
        return Array.from({ length: end - start }, (_, i) => i + start + 1);
      } else {
        return Array.from({ length: now.getMinutes() }, (_, i) => i);
      }
    }
  }
  return [];
};

// 禁用秒
const disabledSeconds = (hour: number, minute: number, type: string) => {
  if (!props.isLimit) return [];
  const now = new Date();
  const selectedDate = type === 'start' ? selectedTimeRange.value.start : selectedTimeRange.value.end;

  if (selectedDate) {
    const selectedDateTime = new Date(selectedDate);
    const isToday = selectedDateTime.getDate() === now.getDate();
    const isCurrentHour = hour === now.getHours();
    const isCurrentMinute = minute === now.getMinutes();

    if (isToday && isCurrentHour && isCurrentMinute) {
      if (props.limitType === 'after') {
        const end = 60;
        const start = now.getSeconds();
        return Array.from({ length: end - start }, (_, i) => i + start + 1);
      } else {
        return Array.from({ length: now.getSeconds() }, (_, i) => i);
      }
    }
  }
  return [];
};
</script>
<style scoped>
/* 根据需要添加样式 */
</style>

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐