Jelajahi Sumber

DatePicker: add attribute defaultTime (#9094)

* DatePicker: add attribute defaultTime

* use createVue instead of createTest & update docs for defaultTime

* update defaultTime type
Hanxing Yang 7 tahun lalu
induk
melakukan
94f18ab9a6

+ 48 - 1
examples/docs/en-US/date-picker.md

@@ -64,7 +64,9 @@
         value8: '',
         value9: '',
         value10: '',
-        value11: ''
+        value11: '',
+        value12: '',
+        value13: ''
       };
     }
   };
@@ -329,6 +331,50 @@ If type is `daterange`, `default-value` sets the left side calendar.
 ```
 :::
 
+###  Default start & end time value
+
+When picking date range on the date panel with type `datetimerange`, `00:00:00` will be used as the default time value for start & end date. We can control it with option `default-time`.
+
+`default-time` accepts an array of string. The first item controls time value of the start date and the second item controls time value of the end date.
+
+:::demo
+```html
+<template>
+  <div class="block">
+    <span class="demonstration">start date time 12:00:00</span>
+    <el-date-picker
+      v-model="value12"
+      type="datetimerange"
+      start-placeholder="Start Date"
+      end-placeholder="End Date"
+      :default-time="['12:00:00']">
+    </el-date-picker>
+  </div>
+  <div class="block">
+    <span class="demonstration">start date time 12:00:00, end date time 08:00:00</span>
+    <el-date-picker
+      v-model="value13"
+      type="datetimerange"
+      start-placeholder="Start Date"
+      end-placeholder="End Date"
+      :default-time="['12:00:00', '08:00:00']">
+    </el-date-picker>
+  </div>
+</template>
+
+<script>
+  export default {
+    data() {
+      return {
+        value12: '',
+        value13: ''
+      };
+    }
+  };
+</script>
+```
+:::
+
 ###  Formatted Value
 
 By default, DatePicker emits `Date` object. You can use `value-format` to designate the format of emitted value, it accepts the same format string of `format` attribute.
@@ -394,6 +440,7 @@ This feature is at alpha stage. Feedback welcome.
 | picker-options | additional options, check the table below | object | — | {} |
 | range-separator | range separator | string | — | '-' |
 | default-value | optional, default date of the calendar | Date | anything accepted by `new Date()` | — |
+| default-time | optional, the time value to use when select datetime range in date table (type `datetimerange`) | string[] | Array with length 2, each item is a string like `12:00:00`. The first item for the start datetime and then second item for the end datetime | — |
 | value-format | optional, format of binding value. If not specified, the binding value will be a Date object | string | year `yyyy`, month `MM`, day `dd`, hour `HH`, minute `mm`, second `ss`, AM/PM `A` | — |
 | name | same as `name` in native input | string | — | — |
 | unlink-panels | unlink two date-panels in range-picker | boolean | — | false |

+ 48 - 1
examples/docs/zh-CN/date-picker.md

@@ -64,7 +64,9 @@
         value8: '',
         value9: '',
         value10: '',
-        value11: ''
+        value11: '',
+        value12: '',
+        value13: ''
       };
     }
   };
@@ -324,6 +326,50 @@
 ```
 :::
 
+###  默认的起始与结束时刻
+
+使用类型`datetimerange`选择时间范围时,在日期选择面板中选定起始与结束的日期,默认会使用该日期的`00:00:00`作为起始与结束的时刻;通过选项`default-time`可以控制选中起始与结束日期时所使用的具体时刻。
+
+`default-time`接受一个数组,数组每项值为字符串,形如`12:00:00`,其中第一项控制起始日期的具体时刻,第二项控制结束日期的具体时刻。
+
+:::demo
+```html
+<template>
+  <div class="block">
+    <span class="demonstration">起始日期时刻为 12:00:00</span>
+    <el-date-picker
+      v-model="value12"
+      type="datetimerange"
+      start-placeholder="开始日期"
+      end-placeholder="结束日期"
+      :default-time="['12:00:00']">
+    </el-date-picker>
+  </div>
+  <div class="block">
+    <span class="demonstration">起始日期时刻为 12:00:00,结束日期时刻为 08:00:00</span>
+    <el-date-picker
+      v-model="value13"
+      type="datetimerange"
+      start-placeholder="开始日期"
+      end-placeholder="结束日期"
+      :default-time="['12:00:00', '08:00:00']">
+    </el-date-picker>
+  </div>
+</template>
+
+<script>
+  export default {
+    data() {
+      return {
+        value12: '',
+        value13: ''
+      };
+    }
+  };
+</script>
+```
+:::
+
 ###  返回值格式
 
 默认情况下,组件接受并返回`Date`对象。
@@ -390,6 +436,7 @@
 | picker-options | 当前时间日期选择器特有的选项参考下表 | object |  — | {} |
 | range-separator | 选择范围时的分隔符 | string | — | '-' |
 | default-value | 可选,选择器打开时默认显示的时间 | Date | 可被`new Date()`解析 | — |
+| default-time | 可选,选择器 type 为 `datetimerange`,范围选择选中日期时所使用的当日内具体时刻 | string[] | 数组,长度为 2,每项值为字符串,形如`12:00:00`,第一项指定开始日期的时刻,第二项指定结束日期的时刻,不指定会使用时刻 `00:00:00` | — |
 | value-format | 可选,绑定值的格式。不指定则绑定值为 Date 对象 | string | 年 `yyyy`,月 `MM`,日 `dd`,小时 `HH`,分 `mm`,秒 `ss`,AM/PM `A` | — |
 | name | 原生属性 | string | — | — |
 | unlink-panels | 在范围选择器里取消两个日期面板之间的联动 | boolean | — | false |

+ 26 - 7
packages/date-picker/src/panel/date-range.vue

@@ -213,6 +213,19 @@
     }
   };
 
+  const modifyWithGivenTime = (date, time) => {
+    if (date == null || time == null) {
+      return date;
+    }
+    time = parseDate(time, 'HH:mm:ss');
+    return modifyTime(
+      date,
+      time.getHours(),
+      time.getMinutes(),
+      time.getSeconds()
+    );
+  };
+
   export default {
     mixins: [Locale],
 
@@ -301,6 +314,7 @@
         popperClass: '',
         value: [],
         defaultValue: null,
+        defaultTime: null,
         minDate: '',
         maxDate: '',
         leftDate: new Date(),
@@ -412,8 +426,9 @@
       },
 
       handleChangeRange(val) {
-        this.minDate = val.minDate;
-        this.maxDate = val.maxDate;
+        const defaultTime = this.defaultTime || [];
+        this.minDate = modifyWithGivenTime(val.minDate, defaultTime[0]);
+        this.maxDate = modifyWithGivenTime(val.maxDate, defaultTime[1]);
         this.rangeState = val.rangeState;
       },
 
@@ -480,17 +495,21 @@
       },
 
       handleRangePick(val, close = true) {
-        if (this.maxDate === val.maxDate && this.minDate === val.minDate) {
+        const defaultTime = this.defaultTime || [];
+        const minDate = modifyWithGivenTime(val.minDate, defaultTime[0]);
+        const maxDate = modifyWithGivenTime(val.maxDate, defaultTime[1]);
+
+        if (this.maxDate === maxDate && this.minDate === minDate) {
           return;
         }
         this.onPick && this.onPick(val);
-        this.maxDate = val.maxDate;
-        this.minDate = val.minDate;
+        this.maxDate = maxDate;
+        this.minDate = minDate;
 
         // workaround for https://github.com/ElemeFE/element/issues/7539, should remove this block when we don't have to care about Chromium 55 - 57
         setTimeout(() => {
-          this.maxDate = val.maxDate;
-          this.minDate = val.minDate;
+          this.maxDate = maxDate;
+          this.minDate = minDate;
         }, 10);
         if (!close || this.showTime) return;
         this.handleConfirm();

+ 2 - 0
packages/date-picker/src/picker.vue

@@ -338,6 +338,7 @@ export default {
     },
     value: {},
     defaultValue: {},
+    defaultTime: {},
     rangeSeparator: {
       default: '-'
     },
@@ -706,6 +707,7 @@ export default {
     mountPicker() {
       this.picker = new Vue(this.panel).$mount();
       this.picker.defaultValue = this.defaultValue;
+      this.picker.defaultTime = this.defaultTime;
       this.picker.popperClass = this.popperClass;
       this.popperElm = this.picker.$el;
       this.picker.width = this.reference.getBoundingClientRect().width;

+ 91 - 0
test/unit/specs/date-picker.spec.js

@@ -1246,6 +1246,97 @@ describe('DatePicker', () => {
       }, DELAY);
     });
 
+    it('select daterange with defaultTime min', done => {
+
+      const vmWithDefaultTime = createVue({
+        template: `
+          <el-date-picker ref="compo" type="datetimerange" v-model="value" :default-time="defaultTime"></el-date-picker>
+        `,
+        data() {
+          return {
+            value: [new Date(2000, 10, 10, 10, 10), new Date(2000, 10, 11, 10, 10)],
+            defaultTime: ['11:59:59']
+          };
+        }
+      }, true).$refs.compo;
+
+      setTimeout(_ => {
+        vmWithDefaultTime.$el.click();
+
+        setTimeout(_ => {
+          const pickers = vmWithDefaultTime.picker.$el.querySelectorAll('.el-date-range-picker__content');
+          const leftCell = pickers[0].querySelector('td.available');
+          const rightCell = pickers[1].querySelector('td.available');
+
+          triggerEvent(leftCell, 'mousemove', true);
+          triggerEvent(leftCell, 'click', true);
+          setTimeout(_ => {
+            triggerEvent(rightCell, 'mousemove', true);
+            triggerEvent(rightCell, 'click', true);
+
+            setTimeout(_ => {
+              const {
+                minDate,
+                maxDate
+              } = vmWithDefaultTime.picker;
+              expect(minDate.getHours()).to.be.equal(11);
+              expect(minDate.getMinutes()).to.be.equal(59);
+              expect(minDate.getSeconds()).to.be.equal(59);
+              expect(maxDate.getHours()).to.be.equal(0);
+              expect(maxDate.getMinutes()).to.be.equal(0);
+              expect(maxDate.getSeconds()).to.be.equal(0);
+              done();
+            }, DELAY);
+          }, DELAY);
+        }, DELAY);
+      }, DELAY * 2); // `DELAY * 2` to ensure this case passes in travis CI
+    });
+
+    it('select daterange with defaultTime min & max', done => {
+      const vmWithDefaultTime = createVue({
+        template: `
+          <el-date-picker ref="compo" type="datetimerange" v-model="value" :default-time="defaultTime"></el-date-picker>
+        `,
+        data() {
+          return {
+            value: [new Date(2000, 10, 10, 10, 10), new Date(2000, 10, 11, 10, 10)],
+            defaultTime: ['11:59:59', '18:00:00']
+          };
+        }
+      }, true).$refs.compo;
+
+      setTimeout(_ => {
+        vmWithDefaultTime.$el.click();
+
+        setTimeout(_ => {
+          const pickers = vmWithDefaultTime.picker.$el.querySelectorAll('.el-date-range-picker__content');
+          const leftCell = pickers[0].querySelector('td.available');
+          const rightCell = pickers[1].querySelector('td.available');
+
+          triggerEvent(leftCell, 'mousemove', true);
+          triggerEvent(leftCell, 'click', true);
+          setTimeout(_ => {
+            triggerEvent(rightCell, 'mousemove', true);
+            triggerEvent(rightCell, 'click', true);
+
+            setTimeout(_ => {
+              const {
+                minDate,
+                maxDate
+              } = vmWithDefaultTime.picker;
+              expect(minDate.getHours()).to.be.equal(11);
+              expect(minDate.getMinutes()).to.be.equal(59);
+              expect(minDate.getSeconds()).to.be.equal(59);
+              expect(maxDate.getHours()).to.be.equal(18);
+              expect(maxDate.getMinutes()).to.be.equal(0);
+              expect(maxDate.getSeconds()).to.be.equal(0);
+              done();
+            }, DELAY);
+          }, DELAY);
+        }, DELAY);
+      }, DELAY * 2); // `DELAY * 2` to ensure this case passes in travis CI
+    });
+
     it('prev/next month button', done => {
       const leftBtn = vm.picker.$el.querySelector('.is-left .el-icon-arrow-left');
       const rightBtn = vm.picker.$el.querySelector('.is-right .el-icon-arrow-right');