0


el-date-picker自定义选择时间&&el-time-select自定义选择时间实现避免时间冲突

需求:开始日期不能小于结束日期,两个选择框之间的互相限制

月份:

固定十二个月,当月开始时间默认选择月第一天,结束时间默认选择月最后一天;

月份选择只允许选择当前月份

天:

将当月对应的每天按照时间段划分,段数不做限制。

时间段支持任意位置插入(新增)、删除。

每个时间段具有包含属性,同一时刻不允许在两个时间段中出现包含。

所有时间段之和必须满足24小时全覆盖且不允许交叉

复制:

点击同上,将上个月份的配置参数拷贝至当前月份

代码实现

开发环境:Vue

需引入插件:ElementUI,moment.js

template

<template>
  <div class='picker-data-time'>
    <el-form-item label="月份" required class="month-picker" v-for="item, index in month_picker_data" :key="index">
      <el-collapse v-model="activeNames" @change="handleChange">
        <slot name="title">
          <div class="title-content">
            <el-col :span="5">
              <el-date-picker v-model="item.start_day" type="date" placeholder="选择日期" @change="sel_change"
                :editable=false value-format="yyyy-MM-dd" :picker-options="picker_options_init(index, 0)"
                :default-value="default_picker_day_start(index)">
              </el-date-picker>
            </el-col>
            <el-col :span="2">
              <center>——</center>
            </el-col>
            <el-col :span="5">
              <el-date-picker v-model="item.end_day" type="date" :editable=false placeholder="选择日期"
                :default-value="default_picker_day_end(index)" :picker-options="picker_options_init(index, 1, item)">
              </el-date-picker>
            </el-col>
            <el-col :span="5">
              <center>
                <el-button type="text" @click="copy_data_from_up(item, index)" v-if="index != 0">同上</el-button>
              </center>
            </el-col>
            <el-col :span="index != 0 ? 5 : 10" style="textAlign:right">
              峰尖平谷
            </el-col>
          </div>
        </slot>
        <el-collapse-item :name="index" class="content-picker-time">
          <table>
            <tr>
              <th v-for="itemy, indey in table_title" :key="indey">{{ itemy }}</th>
            </tr>
            <tr v-for="(itemz, indez) of item.time_picker" :key="indez">
              <td class="table-name">
                <el-select v-model="itemz.time_label" placeholder="请选择">
                  <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
                  </el-option>
                </el-select>
              </td>
              <td>
                <div>
                  <el-col :span="18">
                    <el-time-select v-model="itemz.start_time" :editable="false"
                      :picker-options="picker_time_init(index, indez, 0, itemz)" placeholder="选择时间"
                      :disabled="indez != 0 && month_picker_data[index].time_picker[indez - 1].end_time == ''" />
                  </el-col>
                </div>
                <div style="padding-top: 5%">
                  ( <el-checkbox v-model="itemz.include_start_time" :disabled="is_disable(index, indez, 0, itemz)" />含 )
                </div>
              </td>
              <td>
                <div>
                  <el-col :span="12">
                    <el-time-select v-model="itemz.end_time" :editable="false"
                      :picker-options="picker_time_init(index, indez, 1, itemz)" placeholder="选择时间"
                      :disabled="itemz.start_time == ''" />
                  </el-col>
                </div>
                <div style="padding-top: 7%">
                  ( <el-checkbox v-model="itemz.include_end_time" :disabled="is_disable(index, indez, 1, itemz)" />含 )
                </div>
              </td>
              <td>
                <el-input v-model="itemz.single_price" class="inputTable" />
              </td>
              <td>
                <el-button type="text" @click="del_time_picker(index, indez)">
                  <p style="color: red">删除</p>
                </el-button>
                <el-button type="text" @click="add_time_picker(index, indez)">
                  <p style="color: blue">新增</p>
                </el-button>
              </td>
            </tr>
          </table>
        </el-collapse-item>
      </el-collapse>
    </el-form-item>
  </div>
</template>

js

export default {
  //import引入的组件需要注入到对象中才能使用
  name: 'picker-data-time',
  components: {},
  data() {
    //这里存放数据
    return {
      table_title: ['名称', '起', '止', '单元(元/kWh)', '操作'],
      month_picker_data: [],
      default_time: this.$moment().format(`YYYY-MM-01`),
      activeNames: [],
      start_picker_options: {},
      end_picker_options: {},
      options: [{
        value: 1,
        label: '尖段'
      }, {
        value: 2,
        label: '峰段'
      }, {
        value: 3,
        label: '平段'
      }, {
        value: 4,
        label: '谷段'
      }],
      value: ''
    };
  },
  //监听属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {},
  //方法集合
  methods: {
    create_picker_data() {
      this.month_picker_data = JSON.parse(JSON.stringify(new Array(12)
        .fill({
          start_day: '',
          end_day: '',
          time_picker: [{
            time_label: 1,
            start_time: '',
            include_start_time: false,
            end_time: '',
            include_end_time: false,
            single_price: ''
          }]
        })))
    },
    default_picker_day_start(index) {
      if (this.month_picker_data[index].start_day) return
      const _start_day = this.$moment(new Date(`${new Date().getFullYear()}-${('0' + (+index + 1)).substr(-2)}-01`)).format("YYYY-MM-DD");
      this.month_picker_data[index].start_day = _start_day
      return new Date(_start_day)
    },
    default_picker_day_end(index) {
      if (this.month_picker_data[index].end_day) return
      const _end_day = this.$moment(`
      ${new Date().getFullYear()}-${('0' + (+index + 1)).substr(-2)}-01`)
        .endOf('month').format("YYYY-MM-DD");
      this.month_picker_data[index].end_day = _end_day;
      return new Date(_end_day)
    },
    /**
     * 初始化月份选择区域
     * @param {月份索引} index 
     * @param {0开始、1结束} type 
     * @param {月份对象值} item 
     */
    picker_options_init(index, type, item) {
      if (0 == type) return {
        disabledDate: time => time.getMonth() != index
      }
      if (1 == type) return {
        disabledDate: time => time.getMonth() != index
          || time.getDate() < item.start_day?.substr(-2)
          || time.getFullYear() != item.start_day?.substr(0, 4)
      }
    },
    /**
     * 初始化时间选择
     * @param {*月份索引} index 
     * @param {*日时间分段索引} indez 
     * @param {*类型 0-开始时间 ;1-结束时间} type 
     * @param {* 月份对象} itemz 
     */
    picker_time_init(index, indez, type, itemz) {
      const step = '00:30';
      const step_mins = time_to_mins(step)
      const pick_length = this.month_picker_data[index].time_picker.length
      const prev_itemz = this.month_picker_data[index].time_picker[indez - 1] || {}
      const prev_end_time = prev_itemz.end_time || ''
      const next_itemz = this.month_picker_data[index].time_picker[indez + 1] || {}
      const next_start_time = next_itemz.start_time || ''
      const next_end_time = next_itemz.end_time || ''
      const next_next_start_time = this.month_picker_data[index].time_picker[indez + 2]?.start_time || ''
      const now_end_time = itemz.end_time
      const now_start_time = itemz.start_time
      const result = {
        start: '',
        end: '',
        step
      }
      function time_to_mins(time = '00:00') {
        if (!time) return 0
        const temp_time = time.split(':')
        return temp_time.shift() * 60 + temp_time.shift() * 1
      }
      function mins_to_time(time) {
        if (!time) return '00:00'
        return `${('0' + parseInt(time / 60)).substr(-2)}:${('0' + parseInt(time % 60)).substr(-2)}`
      }
      let temp_arr
      if (0 == type) {
        if (0 == indez) {
          result.start = '00:00';
          temp_arr = [].concat(time_to_mins(now_end_time), time_to_mins(next_start_time), 1440 - step_mins).filter(_ => _ != 0);
          result.end = mins_to_time(Math.min(...temp_arr))
        } else {
          temp_arr = [].concat(time_to_mins(prev_end_time), time_to_mins(next_start_time), time_to_mins(now_end_time)).filter(_ => _ != 0);
          result.start = mins_to_time(Math.min(...temp_arr))
          result.end = mins_to_time(Math.max(...temp_arr))
        }
      }
      if (1 == type) {
        if (indez == 0 && pick_length == 1) {
          result.start = now_start_time
          result.end = mins_to_time(1440);
          return result
        }
        if (indez == pick_length - 1) {
          result.end = mins_to_time(1440);
          temp_arr = [].concat(time_to_mins(now_start_time), time_to_mins(prev_end_time));
          result.start = mins_to_time(Math.max(...temp_arr))
        } else {
          temp_arr = [].concat(time_to_mins(now_start_time), time_to_mins(prev_end_time)).filter(_ => _ != 0)
          let _start = time_to_mins(now_start_time) == 0 ? 0 : Math.max(...temp_arr);
          if (_start < time_to_mins(next_start_time)) {
            result.start = mins_to_time(_start)
            result.end = next_start_time
          }
          else {
            if (next_start_time == '') {
              temp_arr = [].concat(time_to_mins(next_start_time), time_to_mins(next_end_time), time_to_mins(next_next_start_time)).filter(_ => _ != 0);
              const _res = Math.max(...temp_arr)
              const _end = temp_arr.length > 0 ? _res : 1440
              result.start = mins_to_time(_start)
              result.end = mins_to_time(_end)
            } else {
              result.start = ''
              result.end = ''
            }
          }
        }
      }
      return result
    },
    sel_change(val) {
      console.log('sel_change :>> ', val);
    },
    copy_data_from_up(item, index) {
      const source = this.month_picker_data[index - 1].time_picker;
      this.$set(this.month_picker_data[index], 'time_picker', JSON.parse(JSON.stringify(source)))
    },
    handleChange(val) {
      console.log(val);
    },
    del_time_picker(index, indez) {
      this.month_picker_data[index].time_picker.length > 1 && this.month_picker_data[index].time_picker.splice(indez, 1)
    },
    add_time_picker(index, indez) {
      const a = {
        time_label: 1,
        start_time: '',
        include_start_time: false,
        end_time: '',
        include_end_time: false,
        single_price: ''
      };
      this.month_picker_data[index].time_picker.splice(indez + 1, 0, a)
    },
    is_disable(index, indez, type, itemz) {
      if (0 == type) {
        if (indez == 0) {
          const end_time = this.month_picker_data[index].time_picker.at(-1)?.end_time == '24:00' ? '00:00' : ''
          const end_time_include = this.month_picker_data[index].time_picker.at(-1)?.include_end_time;
          return itemz.start_time == end_time && end_time_include
        }
        const prev_end_time = this.month_picker_data[index].time_picker[indez - 1]?.end_time
        const prev_include_end_time = this.month_picker_data[index].time_picker[indez - 1]?.include_end_time
        return prev_end_time == itemz.start_time && prev_include_end_time
      }
      if (1 == type) {
        if (indez == this.month_picker_data[index].time_picker.length - 1) {
          const start_time = this.month_picker_data[index].time_picker.at(0)?.start_time == '00:00' ? '24:00' : ''
          const start_time_include = this.month_picker_data[index].time_picker.at(0)?.include_start_time;
          return start_time_include && start_time == itemz.end_time
        }
        const next_start_time = this.month_picker_data[index].time_picker[indez + 1]?.start_time
        const next_include_start_time = this.month_picker_data[index].time_picker[indez + 1]?.include_start_time
        return next_start_time == itemz.end_time && next_include_start_time
      }
    },
    time_to_mins(time = '00:00') {
      if (!time) return 0
      const temp_time = time.split(':')
      return temp_time.shift() * 60 + temp_time.shift() * 1
    },
    mins_to_time(time) {
      if (!time) return '00:00'
      return `${('0' + parseInt(time / 60)).substr(-2)}:${('0' + parseInt(time % 60)).substr(-2)}`
    },
    data_judgment(result = true) {
      this.month_picker_data.forEach((itemx, index) => {
        try {
          let temp_sum = 0
          itemx.time_picker.forEach((itemy) => {
            const { time_label, start_time, include_start_time, end_time, include_end_time, single_price } = itemy
            if (!time_label || !start_time || !end_time || !single_price) {
              throw new Error(`${index + 1}月输入不完整!`)
            }
            let temp_variable = +include_start_time + (+include_end_time)
            temp_sum += this.time_to_mins(end_time) - this.time_to_mins(start_time) + temp_variable;
          })
          if (temp_sum != 1440 + itemx.time_picker.length) {
            throw new Error(`${index + 1}月时间有误,请检查后重新提交`)
          }
        } catch (error) {
          result = false
          setTimeout(() => {
            this.$message({
              type: 'error',
              message: error
            })
          }, 0)
        }
      })
      return result
    }
  },
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
    this.create_picker_data();
  },
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {

  },
  beforeCreate() { }, //生命周期 - 创建之前
  beforeMount() { }, //生命周期 - 挂载之前
  beforeUpdate() { }, //生命周期 - 更新之前
  updated() { }, //生命周期 - 更新之后
  beforeDestroy() { }, //生命周期 - 销毁之前
  destroyed() { }, //生命周期 - 销毁完成
  activated() { }, //如果页面有keep-alive缓存功能,这个函数会触发
}
         

css

$color: #5859f5;
$bgcColor: #fafafa;

.month-picker {

  // ::v-deep .el-collapse{
  //   // vertical-align: top;
  //   display: flex;
  //   justify-content: space-around;
  //   align-items: center;
  // }
  .title-content {

    // display: flex;
    ::v-deep .el-input {
      margin-top: 3px;
      width: 100%;
    }

    ::v-deep .el-input--suffix .el-input__inner {
      padding-left: 30px;
    }
  }

  .content-picker-time {
    ::v-deep .el-input {
      width: 100%;
    }

    table {
      border-collapse: collapse;
      width: 100%;
    }

    tr {
      padding: 0;
      margin: 0;
      mask-border-width: 1px;
      border: 1px solid #f8f8fb;
      border-left-width: 0px;
      border-right-width: 0px;
    }

    td {
      &.table-name {
        max-width: 140px;
        padding-right: 8px;
      }

      text-align: center;
    }

    th {
      background-color: $bgcColor;
      height: 5vh;
      // width: 30px;
    }
  }
}

效果图

时间起止限制

插入时间限制


本文转载自: https://blog.csdn.net/qq_23355915/article/details/128633293
版权归原作者 David_leil 所有, 如有侵权,请联系我们删除。

“el-date-picker自定义选择时间&&el-time-select自定义选择时间实现避免时间冲突”的评论:

还没有评论