mirror of
https://github.com/element-plus/element-plus.git
synced 2025-02-17 11:49:41 +08:00
Feat/datepicker && datetimepicker (#326)
* chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * chore: update * Feat/form (#342) * feat(form): add form component fix #125 * test(form): add test code * docs(form): add form doc * feat: add uitls merge * fix(form): fix style * test(form): add form test code * refactor(form): review changes * test(form): use idiomatic vue-test-util methods * feat(core): bump vue version * feat(form): rewrite label wrap * feat(form): fix tons of bugs * fix(form): reuse ts extension * refactor(form): move out label width computation * fix(form): fix tons of bugs * fix(form): test Co-authored-by: 286506460 <286506460@qq.com> * Feat/select (#381) * fix: resove conflict * feat: select basic usage * feat: select basic usage * feat: select feature create item * fix: fix option data insert * refactor: select * fix: fix parse error * feat: select test * fix: select add popper * fix: update select option * fix: add select dependency * fix: add index.ts file * fix(select): clean up * fix(select): some refactor * fix(select): some update * fix(select): fix all test cases Co-authored-by: helen <yinhelen.hlj@qq.com> Co-authored-by: Herrington Darkholme <2883231+HerringtonDarkholme@users.noreply.github.com> Co-authored-by: 286506460 <286506460@qq.com> Co-authored-by: helen <yinhelen.hlj@qq.com>
This commit is contained in:
parent
ff4d4d89da
commit
355a778a2c
@ -130,6 +130,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
return {
|
||||
elFormItemSize_,
|
||||
buttonSize,
|
||||
buttonDisabled,
|
||||
handleClick,
|
||||
|
@ -48,12 +48,9 @@ import {
|
||||
} from 'vue'
|
||||
import dayjs, { Dayjs } from 'dayjs'
|
||||
import localeData from 'dayjs/plugin/localeData'
|
||||
import { rangeArr } from '@element-plus/time-picker/src/common/date-utils'
|
||||
dayjs.extend(localeData)
|
||||
|
||||
const rangeArr = n => {
|
||||
return Array.from(Array(n).keys())
|
||||
}
|
||||
|
||||
export const getPrevMonthLastDays = (date: Dayjs, amount) => {
|
||||
const lastDay = date.subtract(1, 'month').endOf('month').date()
|
||||
return rangeArr(amount).map((_, index) => lastDay - (amount - index - 1))
|
||||
|
572
packages/date-picker/__tests__/date-picker.spec.ts
Normal file
572
packages/date-picker/__tests__/date-picker.spec.ts
Normal file
@ -0,0 +1,572 @@
|
||||
import Picker from '@element-plus/time-picker/src/common/picker.vue'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { nextTick } from 'vue'
|
||||
import DatePicker from '../src/date-picker'
|
||||
|
||||
const _mount = (template: string, data = () => ({}), otherObj?) => mount({
|
||||
components: {
|
||||
'el-date-picker': DatePicker,
|
||||
},
|
||||
template,
|
||||
data,
|
||||
...otherObj,
|
||||
}, {
|
||||
global: {
|
||||
provide: {
|
||||
elForm: {},
|
||||
elFormItem: {},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
document.documentElement.innerHTML = ''
|
||||
})
|
||||
|
||||
|
||||
describe('DatePicker', () => {
|
||||
it('create', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
:readonly="true"
|
||||
placeholder='test_'
|
||||
format='HH-mm-ss'
|
||||
/>`)
|
||||
const input = wrapper.find('input')
|
||||
expect(input.attributes('placeholder')).toBe('test_')
|
||||
expect(input.attributes('readonly')).not.toBeUndefined()
|
||||
})
|
||||
|
||||
it('select date', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
/>`, () => ({ value: '' }))
|
||||
const date = dayjs()
|
||||
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const spans = document.querySelectorAll('.el-date-picker__header-label')
|
||||
const arrowLeftElm = document.querySelector('.el-date-picker__prev-btn.el-icon-arrow-left') as HTMLElement
|
||||
const arrowRightElm = document.querySelector('.el-date-picker__next-btn.el-icon-arrow-right') as HTMLElement
|
||||
expect(spans[0].textContent).toContain(date.year())
|
||||
expect(spans[1].textContent).toContain(date.format('MMMM'))
|
||||
const arrowLeftYeayElm = document.querySelector('.el-date-picker__prev-btn.el-icon-d-arrow-left') as HTMLElement
|
||||
arrowLeftYeayElm.click()
|
||||
let count = 20
|
||||
while (--count) {
|
||||
arrowLeftElm.click()
|
||||
}
|
||||
count = 20
|
||||
while (--count) {
|
||||
arrowRightElm.click()
|
||||
}
|
||||
await nextTick()
|
||||
expect(spans[0].textContent).toContain(date.add(-1, 'year').year())
|
||||
expect(spans[1].textContent).toContain(date.format('MMMM'));
|
||||
(document.querySelector('td.available') as HTMLElement).click()
|
||||
await nextTick()
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value).toBeDefined()
|
||||
})
|
||||
|
||||
it('defaultTime and clear value', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
:default-time="new Date(2011,1,1,12,0,1)"
|
||||
/>`, () => ({ value: '' }))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick();
|
||||
(document.querySelector('td.available') as HTMLElement).click()
|
||||
await nextTick()
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value).toBeDefined()
|
||||
expect(vm.value.getHours()).toBe(12)
|
||||
expect(vm.value.getMinutes()).toBe(0)
|
||||
expect(vm.value.getSeconds()).toBe(1)
|
||||
const picker = wrapper.findComponent(Picker);
|
||||
(picker.vm as any).showClose = true
|
||||
await nextTick();
|
||||
(picker.element.querySelector('.el-icon-circle-close') as HTMLElement).click()
|
||||
expect(vm.value).toBeNull()
|
||||
})
|
||||
|
||||
it('event change, focus, blur', async () => {
|
||||
const changeHandler = jest.fn()
|
||||
const focusHandler = jest.fn()
|
||||
const blurHandler = jest.fn()
|
||||
let onChangeValue
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
@change="onChange"
|
||||
@focus="onFocus"
|
||||
@blur="onBlur"
|
||||
/>`, () => ({ value: new Date(2016, 9, 10, 18, 40) }), {
|
||||
methods: {
|
||||
onChange(e) {
|
||||
onChangeValue = e
|
||||
return changeHandler(e)
|
||||
},
|
||||
onFocus(e) {
|
||||
return focusHandler(e)
|
||||
},
|
||||
onBlur(e) {
|
||||
return blurHandler(e)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
expect(focusHandler).toHaveBeenCalledTimes(1);
|
||||
(document.querySelector('td.available') as HTMLElement).click()
|
||||
await nextTick()
|
||||
expect(changeHandler).toHaveBeenCalledTimes(1)
|
||||
expect(blurHandler).toHaveBeenCalledTimes(1)
|
||||
expect(onChangeValue.getTime()).toBe(new Date(2016, 9, 1).getTime())
|
||||
})
|
||||
|
||||
it('shortcuts', async () => {
|
||||
const text = 'Yesterday'
|
||||
const value = new Date(Date.now() - 86400000)
|
||||
value.setHours(0,0,0,0)
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
:shortcuts="shortcuts"
|
||||
/>`, () => ({ value: '', shortcuts: [{
|
||||
text,
|
||||
value,
|
||||
}] }))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const shortcut = document.querySelector('.el-picker-panel__shortcut')
|
||||
expect(shortcut.textContent).toBe(text)
|
||||
expect(document.querySelector('.el-picker-panel__sidebar')).not.toBeNull();
|
||||
(shortcut as HTMLElement).click()
|
||||
await nextTick()
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value.valueOf()).toBe(value.valueOf())
|
||||
})
|
||||
|
||||
it('disabledDate', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
:disabledDate="disabledDate"
|
||||
/>`, () => ({ value: '', disabledDate(time) {
|
||||
return time.getTime() < Date.now() - 8.64e7
|
||||
} }))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
expect(document.querySelector('.disabled')).not.toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('DatePicker Navigation', () => {
|
||||
let prevMonth, prevYear, nextMonth, nextYear, getYearLabel, getMonthLabel
|
||||
|
||||
const initNavigationTest = async value => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
/>`, () => ({ value }))
|
||||
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
prevMonth = document.querySelector('button.el-icon-arrow-left')
|
||||
prevYear = document.querySelector('button.el-icon-d-arrow-left')
|
||||
nextMonth = document.querySelector('button.el-icon-arrow-right')
|
||||
nextYear = document.querySelector('button.el-icon-d-arrow-right')
|
||||
getYearLabel = () => document.querySelectorAll('.el-date-picker__header-label')[0].textContent
|
||||
getMonthLabel = () => document.querySelectorAll('.el-date-picker__header-label')[1].textContent
|
||||
}
|
||||
|
||||
it('month, year', async() => {
|
||||
await initNavigationTest(new Date(2000, 0, 1))
|
||||
expect(getYearLabel()).toContain('2000')
|
||||
expect(getMonthLabel()).toContain('January')
|
||||
|
||||
prevMonth.click()
|
||||
await nextTick()
|
||||
expect(getYearLabel()).toContain('1999')
|
||||
expect(getMonthLabel()).toContain('December')
|
||||
|
||||
prevYear.click()
|
||||
await nextTick()
|
||||
expect(getYearLabel()).toContain('1998')
|
||||
expect(getMonthLabel()).toContain('December')
|
||||
|
||||
nextMonth.click()
|
||||
await nextTick()
|
||||
expect(getYearLabel()).toContain('1999')
|
||||
expect(getMonthLabel()).toContain('January')
|
||||
|
||||
nextYear.click()
|
||||
await nextTick()
|
||||
expect(getYearLabel()).toContain('2000')
|
||||
expect(getMonthLabel()).toContain('January')
|
||||
})
|
||||
|
||||
it('month with fewer dates', async() => {
|
||||
// July has 31 days, June has 30
|
||||
await initNavigationTest(new Date(2000, 6, 31))
|
||||
prevMonth.click()
|
||||
await nextTick()
|
||||
expect(getYearLabel()).toContain('2000')
|
||||
expect(getMonthLabel()).toContain('June')
|
||||
})
|
||||
|
||||
it('year with fewer Feburary dates', async() => {
|
||||
// Feburary 2008 has 29 days, Feburary 2007 has 28
|
||||
await initNavigationTest(new Date(2008, 1, 29))
|
||||
prevYear.click()
|
||||
await nextTick()
|
||||
expect(getYearLabel()).toContain('2007')
|
||||
expect(getMonthLabel()).toContain('February')
|
||||
})
|
||||
|
||||
it('month label with fewer dates', async() => {
|
||||
await initNavigationTest(new Date(2000, 6, 31))
|
||||
const yearLabel = document.querySelectorAll('.el-date-picker__header-label')[0];
|
||||
(yearLabel as HTMLElement).click()
|
||||
await nextTick()
|
||||
const year1999Label = document.querySelectorAll('.el-year-table td a')[1];
|
||||
(year1999Label as HTMLElement).click()
|
||||
await nextTick()
|
||||
const juneLabel = document.querySelectorAll('.el-month-table td a')[5];
|
||||
(juneLabel as HTMLElement).click()
|
||||
await nextTick()
|
||||
expect(getYearLabel()).toContain('2001')
|
||||
expect(getMonthLabel()).toContain('June')
|
||||
const monthLabel = document.querySelectorAll('.el-date-picker__header-label')[1];
|
||||
(monthLabel as HTMLElement).click()
|
||||
await nextTick()
|
||||
const janLabel = document.querySelectorAll('.el-month-table td a')[0];
|
||||
(janLabel as HTMLElement).click()
|
||||
await nextTick()
|
||||
expect(getYearLabel()).toContain('2001')
|
||||
expect(getMonthLabel()).toContain('January')
|
||||
})
|
||||
})
|
||||
|
||||
describe('MonthPicker', () => {
|
||||
it('basic', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
type='month'
|
||||
v-model="value"
|
||||
/>`, () => ({ value: new Date(2020, 7, 1) }))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
expect((document.querySelector('.el-month-table') as HTMLElement).style.display).toBe('')
|
||||
expect(document.querySelector('.el-year-table')).toBeNull();
|
||||
(document.querySelector('.el-month-table a.cell') as HTMLElement).click()
|
||||
await nextTick()
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value.getMonth()).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('YearPicker', () => {
|
||||
it('basic', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
type='year'
|
||||
v-model="value"
|
||||
/>`, () => ({ value: new Date(2020, 7, 1) }))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
expect((document.querySelector('.el-year-table') as HTMLElement).style.display).toBe('')
|
||||
expect(document.querySelector('.el-month-table')).toBeNull()
|
||||
|
||||
const leftBtn = document.querySelector('.el-icon-d-arrow-left') as HTMLElement
|
||||
const rightBtn = document.querySelector('.el-icon-d-arrow-right') as HTMLElement
|
||||
let count = 2
|
||||
|
||||
while (--count) {
|
||||
leftBtn.click()
|
||||
}
|
||||
count = 3
|
||||
while (--count) {
|
||||
rightBtn.click()
|
||||
}
|
||||
|
||||
await nextTick();
|
||||
|
||||
(document.querySelector('.el-year-table a.cell') as HTMLElement).click()
|
||||
await nextTick()
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value.getFullYear()).toBe(2030)
|
||||
})
|
||||
})
|
||||
|
||||
describe('WeekPicker', () => {
|
||||
it('create', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
type='week'
|
||||
v-model="value"
|
||||
/>`, () => ({ value: new Date(2020, 7, 15) }))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
expect(document.querySelector('.is-week-mode')).not.toBeNull();
|
||||
// select month still is in week-mode
|
||||
(document.querySelectorAll('.el-date-picker__header-label')[1] as HTMLElement).click()
|
||||
await nextTick();
|
||||
(document.querySelectorAll('.el-month-table .cell')[7] as HTMLElement).click()
|
||||
await nextTick()
|
||||
expect(document.querySelector('.is-week-mode')).not.toBeNull()
|
||||
const numberOfHighlightRows = () => document.querySelectorAll('.el-date-table__row.current').length;
|
||||
(document.querySelector('.el-date-table__row ~ .el-date-table__row td.available') as HTMLElement).click()
|
||||
await nextTick()
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value).not.toBeNull()
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
expect(numberOfHighlightRows()).toBe(1);
|
||||
// test: next month should not have highlight
|
||||
(document.querySelector('.el-icon-arrow-right') as HTMLElement).click()
|
||||
await nextTick()
|
||||
expect(numberOfHighlightRows()).toBe(0);
|
||||
// test: next year should not have highlight
|
||||
(document.querySelector('.el-icon-arrow-left') as HTMLElement).click()
|
||||
await nextTick();
|
||||
(document.querySelector('.el-icon-d-arrow-right') as HTMLElement).click()
|
||||
await nextTick()
|
||||
expect(numberOfHighlightRows()).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('DatePicker dates', () => {
|
||||
it('create', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
type='dates'
|
||||
v-model="value"
|
||||
/>`, () => ({ value: '' }))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const td = (document.querySelectorAll('.el-date-table__row .available') as NodeListOf<HTMLElement>)
|
||||
const vm = wrapper.vm as any
|
||||
td[0].click()
|
||||
await nextTick()
|
||||
expect(vm.value.length).toBe(1)
|
||||
td[1].click()
|
||||
await nextTick()
|
||||
expect(vm.value.length).toBe(2)
|
||||
expect(document.querySelectorAll('.el-date-table__row .selected').length).toBe(2)
|
||||
td[0].click()
|
||||
await nextTick()
|
||||
expect(vm.value.length).toBe(1)
|
||||
td[1].click()
|
||||
await nextTick()
|
||||
expect(vm.value.length).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('DateRangePicker', () => {
|
||||
|
||||
it('create', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
type='daterange'
|
||||
v-model="value"
|
||||
/>`, () => ({ value: '' }))
|
||||
const inputs = wrapper.findAll('input')
|
||||
inputs[0].trigger('blur')
|
||||
inputs[0].trigger('focus')
|
||||
await nextTick()
|
||||
|
||||
const panels = document.querySelectorAll('.el-date-range-picker__content')
|
||||
expect(panels.length).toBe(2);
|
||||
(panels[0].querySelector('td.available') as HTMLElement).click()
|
||||
await nextTick();
|
||||
(panels[1].querySelector('td.available') as HTMLElement).click()
|
||||
await nextTick()
|
||||
inputs[0].trigger('blur')
|
||||
inputs[0].trigger('focus')
|
||||
await nextTick()
|
||||
// correct highlight
|
||||
const startDate = document.querySelectorAll('.start-date')
|
||||
const endDate = document.querySelectorAll('.end-date')
|
||||
const inRangeDate = document.querySelectorAll('.in-range')
|
||||
expect(startDate.length).toBe(1)
|
||||
expect(endDate.length).toBe(1)
|
||||
expect(inRangeDate.length).toBeGreaterThan(28)
|
||||
// value is array
|
||||
const vm = wrapper.vm as any
|
||||
expect(Array.isArray(vm.value)).toBeTruthy()
|
||||
// input text is something like date string
|
||||
expect(inputs[0].element.value.length).toBe(10)
|
||||
expect(inputs[1].element.value.length).toBe(10)
|
||||
})
|
||||
|
||||
it('reverse selection', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
type='daterange'
|
||||
v-model="value"
|
||||
/>`, () => ({ value: '' }))
|
||||
const inputs = wrapper.findAll('input')
|
||||
inputs[0].trigger('blur')
|
||||
inputs[0].trigger('focus')
|
||||
await nextTick()
|
||||
|
||||
const panels = document.querySelectorAll('.el-date-range-picker__content');
|
||||
(panels[1].querySelector('td.available') as HTMLElement).click()
|
||||
await nextTick();
|
||||
(panels[0].querySelector('td.available') as HTMLElement).click()
|
||||
await nextTick()
|
||||
inputs[0].trigger('blur')
|
||||
inputs[0].trigger('focus')
|
||||
await nextTick()
|
||||
// correct highlight
|
||||
const startDate = document.querySelectorAll('.start-date')
|
||||
const endDate = document.querySelectorAll('.end-date')
|
||||
const inRangeDate = document.querySelectorAll('.in-range')
|
||||
expect(startDate.length).toBe(1)
|
||||
expect(endDate.length).toBe(1)
|
||||
expect(inRangeDate.length).toBeGreaterThan(28)
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value[0].getTime() < vm.value[1].getTime()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('unlink:true', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
type='daterange'
|
||||
v-model="value"
|
||||
unlink-panels
|
||||
/>`, () => ({ value: [new Date(2000, 9, 1), new Date(2000, 11, 2)] }))
|
||||
const inputs = wrapper.findAll('input')
|
||||
inputs[0].trigger('blur')
|
||||
inputs[0].trigger('focus')
|
||||
await nextTick()
|
||||
const panels = document.querySelectorAll('.el-date-range-picker__content')
|
||||
const left = panels[0].querySelector('.el-date-range-picker__header')
|
||||
const right = panels[1].querySelector('.is-right .el-date-range-picker__header')
|
||||
expect(left.textContent).toBe('2000 October')
|
||||
expect(right.textContent).toBe('2000 December');
|
||||
(panels[1].querySelector('.el-icon-d-arrow-right') as HTMLElement).click()
|
||||
await nextTick();
|
||||
(panels[1].querySelector('.el-icon-arrow-right') as HTMLElement).click()
|
||||
await nextTick()
|
||||
expect(left.textContent).toBe('2000 October')
|
||||
expect(right.textContent).toBe('2002 January')
|
||||
})
|
||||
|
||||
it('daylight saving time highlight', async() => {
|
||||
// Run test with environment variable TZ=Australia/Sydney
|
||||
// The following test uses Australian Eastern Daylight Time (AEDT)
|
||||
// AEST -> AEDT shift happened on 2016-10-02 02:00:00
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
type='daterange'
|
||||
v-model="value"
|
||||
unlink-panels
|
||||
/>`, () => ({ value: [new Date(2016, 9, 1), new Date(2016, 9, 3)] }))
|
||||
|
||||
const inputs = wrapper.findAll('input')
|
||||
inputs[0].trigger('blur')
|
||||
inputs[0].trigger('focus')
|
||||
await nextTick()
|
||||
|
||||
const startDate = document.querySelectorAll('.start-date')
|
||||
const endDate = document.querySelectorAll('.end-date')
|
||||
expect(startDate.length).toBe(1)
|
||||
expect(endDate.length).toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('MonthRange', () => {
|
||||
it('works', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
type='monthrange'
|
||||
v-model="value"
|
||||
/>`, () => ({ value: '' }))
|
||||
|
||||
const inputs = wrapper.findAll('input')
|
||||
inputs[0].trigger('blur')
|
||||
inputs[0].trigger('focus')
|
||||
await nextTick()
|
||||
const panels = document.querySelectorAll('.el-date-range-picker__content')
|
||||
expect(panels.length).toBe(2)
|
||||
const p0 = <HTMLElement>panels[0].querySelector('td:not(.disabled)')
|
||||
p0.click()
|
||||
await nextTick()
|
||||
const p1 = (<HTMLElement>panels[1].querySelector('td:not(.disabled)'))
|
||||
p1.click()
|
||||
await nextTick()
|
||||
inputs[0].trigger('blur')
|
||||
inputs[0].trigger('focus')
|
||||
// correct highlight
|
||||
const startDate = document.querySelectorAll('.start-date')
|
||||
const endDate = document.querySelectorAll('.end-date')
|
||||
const inRangeDate = document.querySelectorAll('.in-range')
|
||||
expect(startDate.length).toBe(1)
|
||||
expect(endDate.length).toBe(1)
|
||||
expect(inRangeDate.length).toBeGreaterThan(0)
|
||||
// value is array
|
||||
const vm = wrapper.vm as any
|
||||
expect(Array.isArray(vm.value)).toBeTruthy()
|
||||
// input text is something like date string
|
||||
expect(inputs[0].element.value.length).toBe(7)
|
||||
expect(inputs[1].element.value.length).toBe(7)
|
||||
// reverse selection
|
||||
p1.click()
|
||||
await nextTick()
|
||||
p0.click()
|
||||
await nextTick()
|
||||
expect(vm.value[0].getTime() < vm.value[1].getTime()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('type:monthrange unlink:true', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
type='monthrange'
|
||||
v-model="value"
|
||||
unlink-panels
|
||||
/>`, () => ({ value: [new Date(2000, 9), new Date(2002, 11)] }))
|
||||
|
||||
const inputs = wrapper.findAll('input')
|
||||
inputs[0].trigger('blur')
|
||||
inputs[0].trigger('focus')
|
||||
await nextTick()
|
||||
const panels = document.querySelectorAll('.el-date-range-picker__content')
|
||||
const left = panels[0].querySelector('.el-date-range-picker__header')
|
||||
const right = panels[1].querySelector('.is-right .el-date-range-picker__header')
|
||||
expect(left.textContent).toContain(2000)
|
||||
expect(right.textContent).toContain(2002);
|
||||
(panels[1].querySelector('.el-icon-d-arrow-right') as HTMLElement).click()
|
||||
await nextTick()
|
||||
expect(left.textContent).toContain(2000)
|
||||
expect(right.textContent).toContain(2003)
|
||||
})
|
||||
|
||||
it('daylight saving time highlight', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
type='monthrange'
|
||||
v-model="value"
|
||||
unlink-panels
|
||||
/>`, () => ({ value: [new Date(2016, 6), new Date(2016, 12)] }))
|
||||
|
||||
const inputs = wrapper.findAll('input')
|
||||
inputs[0].trigger('blur')
|
||||
inputs[0].trigger('focus')
|
||||
await nextTick()
|
||||
const startDate = document.querySelectorAll('.start-date')
|
||||
const endDate = document.querySelectorAll('.end-date')
|
||||
expect(startDate.length).toBe(1)
|
||||
expect(endDate.length).toBe(1)
|
||||
})
|
||||
})
|
||||
|
480
packages/date-picker/__tests__/date-time-picker.spec.ts
Normal file
480
packages/date-picker/__tests__/date-time-picker.spec.ts
Normal file
@ -0,0 +1,480 @@
|
||||
import { triggerEvent } from '@element-plus/test-utils'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { nextTick } from 'vue'
|
||||
import DatePicker from '../src/date-picker'
|
||||
|
||||
const formatStr = 'YYYY-MM-DD HH:mm:ss'
|
||||
const makeRange = (start, end) => {
|
||||
const result = []
|
||||
for (let i = start; i <= end; i++) {
|
||||
result.push(i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
const _mount = (template: string, data = () => ({}), otherObj?) => mount({
|
||||
components: {
|
||||
'el-date-picker': DatePicker,
|
||||
},
|
||||
template,
|
||||
data,
|
||||
...otherObj,
|
||||
}, {
|
||||
global: {
|
||||
provide: {
|
||||
elForm: {},
|
||||
elFormItem: {},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
document.documentElement.innerHTML = ''
|
||||
})
|
||||
|
||||
|
||||
describe('Datetime Picker', () => {
|
||||
|
||||
it('both picker show correct formated value (extract date-format and time-format from format property', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetime"
|
||||
:format="format"
|
||||
/>`, () => ({
|
||||
value: new Date(2018, 2, 5, 10, 15, 24),
|
||||
format: 'YYYY/MM/DD HH:mm A',
|
||||
}))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const dateInput = document.querySelector('.el-date-picker__time-header > span:nth-child(1) input')
|
||||
const timeInput = document.querySelector('.el-date-picker__time-header > span:nth-child(2) input');
|
||||
(timeInput as HTMLElement).focus()
|
||||
await nextTick()
|
||||
// both input shows correct value
|
||||
expect((dateInput as HTMLInputElement).value).toBe('2018/03/05')
|
||||
expect((timeInput as HTMLInputElement).value).toBe('10:15 AM')
|
||||
wrapper.setProps({
|
||||
format: 'MM-DD-YYYY HH a',
|
||||
})
|
||||
await nextTick()
|
||||
expect((dateInput as HTMLInputElement).value).toBe('03-05-2018')
|
||||
expect((timeInput as HTMLInputElement).value).toBe('10 am')
|
||||
})
|
||||
|
||||
it('both picker show correct value', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetime"
|
||||
/>`, () => ({
|
||||
value: new Date(2000, 9, 1, 10, 0, 1),
|
||||
}))
|
||||
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const dateInput = document.querySelector('.el-date-picker__time-header > span:nth-child(1) input')
|
||||
const timeInput = document.querySelector('.el-date-picker__time-header > span:nth-child(2) input');
|
||||
(timeInput as HTMLElement).focus()
|
||||
await nextTick()
|
||||
// both input shows correct value
|
||||
expect((dateInput as HTMLInputElement).value).toBe('2000-10-01')
|
||||
expect((timeInput as HTMLInputElement).value).toBe('10:00:01')
|
||||
// time spinner highlight is correct
|
||||
let spinners = document.querySelectorAll('.el-time-spinner ul li.active') as any
|
||||
expect(spinners[0].textContent).toBe('10')
|
||||
expect(spinners[1].textContent).toBe('00')
|
||||
expect(spinners[2].textContent).toBe('01')
|
||||
wrapper.setProps({
|
||||
modelValue: new Date(2001, 10, 2, 11, 1, 2),
|
||||
})
|
||||
await nextTick()
|
||||
spinners = document.querySelectorAll('.el-time-spinner ul li.active') as any
|
||||
expect((dateInput as HTMLInputElement).value).toBe('2001-11-02')
|
||||
expect((timeInput as HTMLInputElement).value).toBe('11:01:02')
|
||||
expect(spinners[0].textContent).toBe('11')
|
||||
expect(spinners[1].textContent).toBe('01')
|
||||
expect(spinners[2].textContent).toBe('02')
|
||||
})
|
||||
|
||||
it('click now button', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetime"
|
||||
/>`, () => ({
|
||||
value: '',
|
||||
}))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick();
|
||||
(document.querySelector('.el-picker-panel__link-btn') as HTMLElement).click()
|
||||
await nextTick()
|
||||
const vm = wrapper.vm as any
|
||||
// test if is current time (deviation 10 seconds)
|
||||
expect(dayjs(vm.value).diff(dayjs()) < 10).toBeTruthy()
|
||||
})
|
||||
|
||||
it('timepicker select && input time && input date', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetime"
|
||||
/>`, () => ({
|
||||
value: '',
|
||||
}))
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value).toBe('')
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const input_ = document.querySelectorAll('.el-date-picker__editor-wrap input')[1];
|
||||
(input_ as HTMLElement).focus()
|
||||
await nextTick()
|
||||
const timePanel = document.querySelector('.el-time-panel')
|
||||
expect(timePanel.querySelector('.el-time-spinner').innerHTML).not.toBeNull()
|
||||
const button = document.querySelector('.el-time-panel .confirm') as HTMLElement
|
||||
button.click()
|
||||
await nextTick()
|
||||
expect(vm.value).not.toBe('')
|
||||
const timeInput = document.querySelectorAll('.el-date-picker__editor-wrap input')[1] as HTMLInputElement
|
||||
timeInput.value = '20:30:33'
|
||||
timeInput.dispatchEvent(new Event('change'))
|
||||
await nextTick()
|
||||
const valueResult = dayjs(vm.value)
|
||||
expect(valueResult.hour()).toBe(20)
|
||||
expect(valueResult.minute()).toBe(30)
|
||||
expect(valueResult.second()).toBe(33)
|
||||
const dateInput = document.querySelector('.el-date-picker__editor-wrap input') as HTMLInputElement
|
||||
dateInput.value = '2017-02-02'
|
||||
dateInput.dispatchEvent(new Event('change'))
|
||||
await nextTick()
|
||||
const valueResult2 = dayjs(vm.value)
|
||||
expect(valueResult2.year()).toBe(2017)
|
||||
expect(valueResult2.month()).toBe(1)
|
||||
expect(valueResult2.date()).toBe(2)
|
||||
})
|
||||
|
||||
it('now button: can not choose disabled date', async () => {
|
||||
let isDisable = true
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetime"
|
||||
:disabledDate="disabledDate"
|
||||
/>`, () => ({
|
||||
value: '',
|
||||
disabledDate() {
|
||||
return isDisable
|
||||
},
|
||||
}))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
// click now button
|
||||
const btn = document.querySelector('.el-picker-panel__footer .el-button--text') as HTMLElement
|
||||
btn.click()
|
||||
await nextTick()
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value).toBe('')
|
||||
isDisable = false
|
||||
await nextTick()
|
||||
btn.click()
|
||||
await nextTick()
|
||||
expect(vm.value).not.toBe('')
|
||||
})
|
||||
|
||||
it('confirm button honors picked date', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetime"
|
||||
/>`, () => ({
|
||||
value: new Date(2000, 9, 1, 12, 0, 0), // 2010-10-01 12:00:00
|
||||
}))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick();
|
||||
// changed month / year should not effect picked time
|
||||
(document.querySelector('.el-date-picker__header .el-icon-arrow-right') as HTMLElement).click();
|
||||
(document.querySelector('.el-date-picker__header .el-icon-d-arrow-right') as HTMLElement).click();
|
||||
// click confirm button
|
||||
(document.querySelector('.el-picker-panel__footer .el-button--default') as HTMLElement).click()
|
||||
const vm = wrapper.vm as any
|
||||
expect(dayjs(vm.value).format(formatStr)).toBe('2000-10-01 12:00:00')
|
||||
})
|
||||
|
||||
it('selectableRange', async () => {
|
||||
const disabledHoursArr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,23]
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetime"
|
||||
:disabledHours="disabledHours"
|
||||
:disabledMinutes="disabledMinutes"
|
||||
:disabledSeconds="disabledSeconds"
|
||||
/>`, () => ({
|
||||
value: new Date(2019, 0, 1, 18, 50) }),
|
||||
{
|
||||
methods: {
|
||||
disabledHours() {
|
||||
return disabledHoursArr
|
||||
},
|
||||
disabledMinutes (hour) {
|
||||
// ['17:30:00 - 18:30:00', '18:50:00 - 20:30:00', '21:00:00 - 22:00:00']
|
||||
if (hour === 17) {
|
||||
return makeRange(0, 29)
|
||||
}
|
||||
if (hour === 18) {
|
||||
return makeRange(31, 49)
|
||||
}
|
||||
if (hour === 20) {
|
||||
return makeRange(31, 59)
|
||||
}
|
||||
if (hour === 22) {
|
||||
return makeRange(1, 59)
|
||||
}
|
||||
},
|
||||
disabledSeconds(hour, minute) {
|
||||
if (hour === 18 && minute === 30) {
|
||||
return makeRange(1, 59)
|
||||
}
|
||||
if (hour === 20 && minute === 30) {
|
||||
return makeRange(1, 59)
|
||||
}
|
||||
if (hour === 22 && minute === 0) {
|
||||
return makeRange(1, 59)
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const input1 = document.querySelectorAll('.el-date-picker__editor-wrap input')[1] as HTMLInputElement
|
||||
input1.blur()
|
||||
input1.focus()
|
||||
await nextTick()
|
||||
const list = document.querySelectorAll('.el-time-spinner__list')
|
||||
const hoursEl = list[0]
|
||||
const disabledHours = [].slice
|
||||
.call(hoursEl.querySelectorAll('.disabled'))
|
||||
.map(node => Number(node.textContent))
|
||||
expect(disabledHours).toStrictEqual(disabledHoursArr)
|
||||
const minutesEl = list[1]
|
||||
const disabledMinutes = [].slice
|
||||
.call(minutesEl.querySelectorAll('.disabled'))
|
||||
.map(node => Number(node.textContent))
|
||||
expect(disabledMinutes.length).toBe(19)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Datetimerange', () => {
|
||||
|
||||
it('select daterange and default Time and input format', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetimerange"
|
||||
:defaultTime="new Date(2020, 1, 1, 1, 1, 1)"
|
||||
format="YYYY/MM/DD HH:mm A"
|
||||
/>`, () => ({
|
||||
value: [new Date(2000, 10, 8, 10, 10), new Date(2000, 10, 11, 10, 10)],
|
||||
}))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const pickers = document.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)
|
||||
await nextTick()
|
||||
triggerEvent(rightCell, 'mousemove', true)
|
||||
triggerEvent(rightCell, 'click', true)
|
||||
await nextTick();
|
||||
(document.querySelector('.el-picker-panel__footer .el-button--default') as HTMLElement).click()
|
||||
await nextTick()
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value.map(_ => dayjs(_).format(formatStr)))
|
||||
.toStrictEqual(['2000-11-01 01:01:01', '2000-12-01 01:01:01'])
|
||||
const pickerss = document.querySelectorAll('.el-date-range-picker__time-header .el-date-range-picker__editors-wrap')
|
||||
const left = {
|
||||
dateInput: pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(1) input'),
|
||||
timeInput: pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(2) input'),
|
||||
}
|
||||
const right = {
|
||||
dateInput: pickerss[1].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(1) input'),
|
||||
timeInput: pickerss[1].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(2) input'),
|
||||
}
|
||||
await nextTick()
|
||||
// both input shows correct value
|
||||
expect((left.dateInput as HTMLInputElement).value).toBe('2000/11/01')
|
||||
expect((left.timeInput as HTMLInputElement).value).toBe('01:01 AM')
|
||||
expect((right.dateInput as HTMLInputElement).value).toBe('2000/12/01')
|
||||
expect((right.timeInput as HTMLInputElement).value).toBe('01:01 AM')
|
||||
})
|
||||
|
||||
it('input date', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetimerange"
|
||||
/>`, () => ({
|
||||
value: '',
|
||||
}))
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const pickerss = document.querySelectorAll('.el-date-range-picker__time-header .el-date-range-picker__editors-wrap')
|
||||
const leftDateInput = pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(1) input') as HTMLInputElement
|
||||
const rightDateInput = pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(1) input') as HTMLInputElement
|
||||
leftDateInput.value = '1999-03-04'
|
||||
triggerEvent(leftDateInput, 'input', true)
|
||||
triggerEvent(leftDateInput, 'change', true)
|
||||
await nextTick()
|
||||
const pickers = document.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)
|
||||
await nextTick()
|
||||
triggerEvent(rightCell, 'mousemove', true)
|
||||
triggerEvent(rightCell, 'click', true)
|
||||
await nextTick()
|
||||
const btn = document.querySelector('.el-picker-panel__footer .el-button--default') as HTMLElement
|
||||
btn.click()
|
||||
await nextTick()
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value.map(_ => dayjs(_).format(formatStr)))
|
||||
.toStrictEqual(['1999-03-01 00:00:00','1999-04-01 00:00:00'])
|
||||
// input date when minDate > maxDate
|
||||
rightDateInput.value = '1998-01-01'
|
||||
triggerEvent(rightDateInput, 'input', true)
|
||||
triggerEvent(rightDateInput, 'change', true)
|
||||
await nextTick()
|
||||
btn.click()
|
||||
await nextTick()
|
||||
expect(dayjs(vm.value[0]).isBefore(vm.value[1])).toBeTruthy()
|
||||
})
|
||||
|
||||
|
||||
it('select time', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetimerange"
|
||||
/>`, () => ({
|
||||
value: '',
|
||||
}))
|
||||
const vm = wrapper.vm as any
|
||||
expect(vm.value).toBe('')
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const timeInput = document.querySelectorAll('.el-date-range-picker__editors-wrap input')[1] as HTMLInputElement
|
||||
timeInput.blur()
|
||||
timeInput.focus()
|
||||
timeInput.blur()
|
||||
await nextTick()
|
||||
const button = document.querySelector('.el-date-range-picker__time-picker-wrap .el-time-panel .confirm') as HTMLElement
|
||||
button.click()
|
||||
await nextTick()
|
||||
const btn = document.querySelector('.el-picker-panel__footer .el-button--default') as HTMLElement
|
||||
btn.click()
|
||||
await nextTick()
|
||||
expect(vm.value).not.toBe('')
|
||||
})
|
||||
|
||||
it('confirm honors disabledDate', async () => {
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetimerange"
|
||||
:disabledDate="disabledDate"
|
||||
/>`, () => ({
|
||||
value: '',
|
||||
disabledDate: date => {
|
||||
return date.getTime() < new Date(2000, 9, 1) // 2000-10-01
|
||||
},
|
||||
}))
|
||||
const vm = wrapper.vm as any
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
// simulate user input of invalid date
|
||||
const pickerss = document.querySelectorAll('.el-date-range-picker__time-header .el-date-range-picker__editors-wrap')
|
||||
const leftDateInput = pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(1) input') as HTMLInputElement
|
||||
leftDateInput.value = '2000-09-01'
|
||||
triggerEvent(leftDateInput, 'input', true)
|
||||
triggerEvent(leftDateInput, 'change', true)
|
||||
await nextTick()
|
||||
const btn = document.querySelector('.el-picker-panel__footer .el-button--default') as HTMLElement
|
||||
expect(btn.getAttribute('disabled')).not.toBeUndefined() // invalid input disables button
|
||||
btn.click()
|
||||
await nextTick()
|
||||
const rangePanel = document.querySelector('.el-date-range-picker')
|
||||
expect(rangePanel.getAttribute('visible')).toBe('true') // popper still open
|
||||
expect(vm.value).toBe('')
|
||||
leftDateInput.value = '2001-09-01'
|
||||
triggerEvent(leftDateInput, 'input', true)
|
||||
triggerEvent(leftDateInput, 'change', true)
|
||||
await nextTick()
|
||||
expect(btn.getAttribute('disabled')).not.toBeUndefined()
|
||||
btn.click()
|
||||
await nextTick()
|
||||
expect(rangePanel.getAttribute('visible')).toBe('false') // popper dismiss
|
||||
expect(vm.value).not.toBe('')
|
||||
})
|
||||
|
||||
it('selectableRange', async () => {
|
||||
const disabledHoursArr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,23]
|
||||
const disabledHoursRightArr = [0,1,2]
|
||||
const wrapper = _mount(`<el-date-picker
|
||||
v-model="value"
|
||||
type="datetimerange"
|
||||
:disabledHours="disabledHours"
|
||||
/>`, () => ({
|
||||
value: '' }),
|
||||
{
|
||||
methods: {
|
||||
disabledHours(role) {
|
||||
if (role === 'end') {
|
||||
return disabledHoursRightArr
|
||||
}
|
||||
return disabledHoursArr
|
||||
},
|
||||
},
|
||||
})
|
||||
const input = wrapper.find('input')
|
||||
input.trigger('blur')
|
||||
input.trigger('focus')
|
||||
await nextTick()
|
||||
const pickerss = document.querySelectorAll('.el-date-range-picker__time-header .el-date-range-picker__editors-wrap')
|
||||
const leftDateInput = pickerss[0].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(2) input') as HTMLInputElement
|
||||
const rightDateInput = pickerss[1].querySelector('.el-date-range-picker__time-picker-wrap:nth-child(2) input') as HTMLInputElement
|
||||
leftDateInput.blur()
|
||||
leftDateInput.focus()
|
||||
await nextTick()
|
||||
const listleft = document.querySelectorAll('.el-date-range-picker__editors-wrap .el-time-spinner__list')
|
||||
const hoursEl = listleft[0]
|
||||
const disabledHours = [].slice
|
||||
.call(hoursEl.querySelectorAll('.disabled'))
|
||||
.map(node => Number(node.textContent))
|
||||
expect(disabledHours).toStrictEqual(disabledHoursArr)
|
||||
const button = document.querySelector('.el-date-range-picker__time-picker-wrap .el-time-panel .confirm') as HTMLElement
|
||||
button.click()
|
||||
await nextTick()
|
||||
rightDateInput.blur()
|
||||
rightDateInput.focus()
|
||||
await nextTick()
|
||||
const listright = document.querySelectorAll('.el-date-range-picker__editors-wrap.is-right .el-time-spinner__list')
|
||||
const hoursEl2 = listright[0]
|
||||
const disabledHours2 = [].slice
|
||||
.call(hoursEl2.querySelectorAll('.disabled'))
|
||||
.map(node => Number(node.textContent))
|
||||
expect(disabledHours2).toStrictEqual(disabledHoursRightArr)
|
||||
})
|
||||
})
|
5
packages/date-picker/index.ts
Normal file
5
packages/date-picker/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { App } from 'vue'
|
||||
import DatePicker from './src/date-picker'
|
||||
export default (app: App): void => {
|
||||
app.component(DatePicker.name, DatePicker)
|
||||
}
|
12
packages/date-picker/package.json
Normal file
12
packages/date-picker/package.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "@element-plus/date-picker",
|
||||
"version": "0.0.0",
|
||||
"main": "dist/index.js",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"vue": "^3.0.0-rc.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/test-utils": "^2.0.0-beta.3"
|
||||
}
|
||||
}
|
385
packages/date-picker/src/date-picker-com/basic-date-table.vue
Normal file
385
packages/date-picker/src/date-picker-com/basic-date-table.vue
Normal file
@ -0,0 +1,385 @@
|
||||
<template>
|
||||
<table
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
class="el-date-table"
|
||||
:class="{ 'is-week-mode': selectionMode === 'week' }"
|
||||
@click="handleClick"
|
||||
@mousemove="handleMouseMove"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th v-if="showWeekNumber">{{ t('el.datepicker.week') }}</th>
|
||||
<th v-for="(week, key) in WEEKS" :key="key">{{ t('el.datepicker.weeks.' + week) }}</th>
|
||||
</tr>
|
||||
<tr
|
||||
v-for="(row, key) in rows"
|
||||
:key="key"
|
||||
class="el-date-table__row"
|
||||
:class="{ current: isWeekActive(row[1]) }"
|
||||
>
|
||||
<td
|
||||
v-for="(cell, key_) in row"
|
||||
:key="key_"
|
||||
:class="getCellClasses(cell)"
|
||||
>
|
||||
<div>
|
||||
<span>
|
||||
{{ cell.text }}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { t } from '@element-plus/locale'
|
||||
import {
|
||||
coerceTruthyValueToArray,
|
||||
} from '@element-plus/utils/util'
|
||||
|
||||
|
||||
import {
|
||||
defineComponent,
|
||||
computed,
|
||||
ref,
|
||||
PropType,
|
||||
} from 'vue'
|
||||
import dayjs, { Dayjs } from 'dayjs'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
date: {
|
||||
type: Dayjs as PropType<Dayjs>,
|
||||
},
|
||||
minDate: {
|
||||
type: Dayjs as PropType<Dayjs>,
|
||||
},
|
||||
maxDate: {
|
||||
type: Dayjs as PropType<Dayjs>,
|
||||
},
|
||||
parsedValue: {
|
||||
type: [Object, Array] as PropType<Dayjs | Dayjs[]>,
|
||||
},
|
||||
selectionMode: {
|
||||
type: String,
|
||||
default: 'day',
|
||||
},
|
||||
showWeekNumber: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disabledDate: {
|
||||
type: Function,
|
||||
},
|
||||
cellClassName: {
|
||||
type: Function,
|
||||
},
|
||||
rangeState: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
endDate: null,
|
||||
selecting: false,
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['changerange', 'pick', 'select'],
|
||||
|
||||
setup(props, ctx) {
|
||||
// data
|
||||
const lastRow = ref(null)
|
||||
const lastColumn = ref(null)
|
||||
const tableRows = ref([ [], [], [], [], [], [] ])
|
||||
|
||||
// todo better way to get Day.js locale object
|
||||
const firstDayOfWeek = (props.date as any).$locale().weekStart || 7
|
||||
const WEEKS_CONSTANT = props.date.locale('en').localeData().weekdaysShort().map(_=>_.toLowerCase())
|
||||
|
||||
const offsetDay = computed(() => {
|
||||
// Sunday 7(0), cal the left and right offset days, 3217654, such as Monday is -1, the is to adjust the position of the first two rows of dates
|
||||
return firstDayOfWeek > 3 ? 7 - firstDayOfWeek : -firstDayOfWeek
|
||||
})
|
||||
|
||||
const startDate = computed(() => {
|
||||
const startDayOfMonth = props.date.startOf('month')
|
||||
return startDayOfMonth.subtract(startDayOfMonth.day() || 7, 'day')
|
||||
})
|
||||
|
||||
const WEEKS = computed(() => {
|
||||
return WEEKS_CONSTANT.concat(WEEKS_CONSTANT).slice(firstDayOfWeek, firstDayOfWeek + 7)
|
||||
})
|
||||
|
||||
const rows = computed(()=> {
|
||||
// TODO: refactory rows / getCellClasses
|
||||
const startOfMonth = props.date.startOf('month')
|
||||
const startOfMonthDay = startOfMonth.day() || 7 // day of first day
|
||||
const dateCountOfMonth = startOfMonth.daysInMonth()
|
||||
const dateCountOfLastMonth = startOfMonth.subtract(1, 'month').daysInMonth()
|
||||
|
||||
const offset = offsetDay.value
|
||||
const rows_ = tableRows.value
|
||||
let count = 1
|
||||
|
||||
const selectedDate: Dayjs[] = props.selectionMode === 'dates' ? coerceTruthyValueToArray(props.parsedValue) : []
|
||||
|
||||
const calNow = dayjs().startOf('day')
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
const row = rows_[i]
|
||||
|
||||
if (props.showWeekNumber) {
|
||||
if (!row[0]) {
|
||||
row[0] = {
|
||||
type: 'week',
|
||||
text: startDate.value.add(i * 7 + 1, 'day').week(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let j = 0; j < 7; j++) {
|
||||
let cell = row[props.showWeekNumber ? j + 1 : j]
|
||||
if (!cell) {
|
||||
cell = {
|
||||
row: i,
|
||||
column: j,
|
||||
type: 'normal',
|
||||
inRange: false,
|
||||
start: false,
|
||||
end: false,
|
||||
}
|
||||
}
|
||||
const index = i * 7 + j
|
||||
const calTime = startDate.value.add(index - offset, 'day')
|
||||
cell.type = 'normal'
|
||||
|
||||
const calEndDate = props.rangeState.endDate || props.maxDate
|
||||
|| props.rangeState.selecting && props.minDate
|
||||
|
||||
cell.inRange = (
|
||||
props.minDate &&
|
||||
calTime.isSameOrAfter(props.minDate, 'day')
|
||||
) && (calEndDate &&
|
||||
calTime.isSameOrBefore(calEndDate, 'day')
|
||||
)
|
||||
|
||||
cell.start = props.minDate
|
||||
&& calTime.isSame(props.minDate, 'day')
|
||||
|
||||
cell.end = calEndDate && calTime.isSame(calEndDate, 'day')
|
||||
const isToday = calTime.isSame(calNow, 'day')
|
||||
|
||||
if (isToday) {
|
||||
cell.type = 'today'
|
||||
}
|
||||
|
||||
if (i >= 0 && i <= 1) {
|
||||
const numberOfDaysFromPreviousMonth = startOfMonthDay + offset < 0 ? 7 + startOfMonthDay + offset : startOfMonthDay + offset
|
||||
|
||||
if (j + i * 7 >= numberOfDaysFromPreviousMonth) {
|
||||
cell.text = count++
|
||||
} else {
|
||||
cell.text = dateCountOfLastMonth - (numberOfDaysFromPreviousMonth - j % 7) + 1 + i * 7
|
||||
cell.type = 'prev-month'
|
||||
}
|
||||
} else {
|
||||
if (count <= dateCountOfMonth) {
|
||||
cell.text = count++
|
||||
} else {
|
||||
cell.text = count++ - dateCountOfMonth
|
||||
cell.type = 'next-month'
|
||||
}
|
||||
}
|
||||
|
||||
const cellDate = calTime.toDate()
|
||||
cell.selected = selectedDate.find(_ => _.valueOf() === calTime.valueOf())
|
||||
cell.disabled = props.disabledDate && props.disabledDate(cellDate)
|
||||
cell.customClass = props.cellClassName && props.cellClassName(cellDate)
|
||||
row[props.showWeekNumber ? j + 1 : j] = cell
|
||||
}
|
||||
|
||||
if (props.selectionMode === 'week') {
|
||||
const start = props.showWeekNumber ? 1 : 0
|
||||
const end = props.showWeekNumber ? 7 : 6
|
||||
const isActive = isWeekActive(row[start + 1])
|
||||
row[start].inRange = isActive
|
||||
row[start].start = isActive
|
||||
row[end].inRange = isActive
|
||||
row[end].end = isActive
|
||||
}
|
||||
}
|
||||
return rows_
|
||||
})
|
||||
|
||||
const cellMatchesDate = (cell, date) => {
|
||||
if (!date) return false
|
||||
return dayjs(date)
|
||||
.isSame(
|
||||
props.date.date(Number(cell.text))
|
||||
, 'day',
|
||||
)
|
||||
}
|
||||
|
||||
const getCellClasses = cell => {
|
||||
let classes = []
|
||||
if ((cell.type === 'normal' || cell.type === 'today') && !cell.disabled) {
|
||||
classes.push('available')
|
||||
if (cell.type === 'today') {
|
||||
classes.push('today')
|
||||
}
|
||||
} else {
|
||||
classes.push(cell.type)
|
||||
}
|
||||
|
||||
if (props.selectionMode === 'day' && (cell.type === 'normal' || cell.type === 'today') && cellMatchesDate(cell, props.parsedValue)) {
|
||||
classes.push('current')
|
||||
}
|
||||
|
||||
if (cell.inRange && ((cell.type === 'normal' || cell.type === 'today') || props.selectionMode === 'week')) {
|
||||
classes.push('in-range')
|
||||
|
||||
if (cell.start) {
|
||||
classes.push('start-date')
|
||||
}
|
||||
|
||||
if (cell.end) {
|
||||
classes.push('end-date')
|
||||
}
|
||||
}
|
||||
|
||||
if (cell.disabled) {
|
||||
classes.push('disabled')
|
||||
}
|
||||
|
||||
if (cell.selected) {
|
||||
classes.push('selected')
|
||||
}
|
||||
|
||||
if (cell.customClass) {
|
||||
classes.push(cell.customClass)
|
||||
}
|
||||
|
||||
return classes.join(' ')
|
||||
}
|
||||
|
||||
const getDateOfCell = (row, column) => {
|
||||
const offsetFromStart = row * 7 + (column - (props.showWeekNumber ? 1 : 0)) - offsetDay.value
|
||||
return startDate.value.add(offsetFromStart, 'day')
|
||||
}
|
||||
|
||||
const handleMouseMove = event => {
|
||||
if (!props.rangeState.selecting) return
|
||||
|
||||
let target = event.target
|
||||
if (target.tagName === 'SPAN') {
|
||||
target = target.parentNode.parentNode
|
||||
}
|
||||
if (target.tagName === 'DIV') {
|
||||
target = target.parentNode
|
||||
}
|
||||
if (target.tagName !== 'TD') return
|
||||
|
||||
const row = target.parentNode.rowIndex - 1
|
||||
const column = target.cellIndex
|
||||
|
||||
// can not select disabled date
|
||||
if (rows.value[row][column].disabled) return
|
||||
|
||||
// only update rangeState when mouse moves to a new cell
|
||||
// this avoids frequent Date object creation and improves performance
|
||||
if (row !== lastRow.value || column !== lastColumn.value) {
|
||||
lastRow.value = row
|
||||
lastColumn.value = column
|
||||
ctx.emit('changerange', {
|
||||
selecting: true,
|
||||
endDate: getDateOfCell(row, column),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleClick = event => {
|
||||
let target = event.target
|
||||
if (target.tagName === 'SPAN') {
|
||||
target = target.parentNode.parentNode
|
||||
}
|
||||
if (target.tagName === 'DIV') {
|
||||
target = target.parentNode
|
||||
}
|
||||
|
||||
if (target.tagName !== 'TD') return
|
||||
|
||||
const row = target.parentNode.rowIndex - 1
|
||||
const column = props.selectionMode === 'week' ? 1 : target.cellIndex
|
||||
const cell = rows.value[row][column]
|
||||
|
||||
if (cell.disabled || cell.type === 'week') return
|
||||
|
||||
const newDate = getDateOfCell(row, column)
|
||||
|
||||
if (props.selectionMode === 'range') {
|
||||
if (!props.rangeState.selecting) {
|
||||
ctx.emit('pick', { minDate: newDate, maxDate: null })
|
||||
ctx.emit('select', true)
|
||||
} else {
|
||||
if (newDate >= props.minDate) {
|
||||
ctx.emit('pick', { minDate: props.minDate, maxDate: newDate })
|
||||
} else {
|
||||
ctx.emit('pick', { minDate: newDate, maxDate: props.minDate })
|
||||
}
|
||||
ctx.emit('select', false)
|
||||
}
|
||||
} else if (props.selectionMode === 'day') {
|
||||
ctx.emit('pick', newDate)
|
||||
} else if (props.selectionMode === 'week') {
|
||||
const weekNumber = newDate.week()
|
||||
const value = newDate.year() + 'w' + weekNumber
|
||||
ctx.emit('pick', {
|
||||
year: newDate.year(),
|
||||
week: weekNumber,
|
||||
value: value,
|
||||
date: newDate,
|
||||
})
|
||||
} else if (props.selectionMode === 'dates') {
|
||||
const newValue = cell.selected
|
||||
? coerceTruthyValueToArray(props.parsedValue).filter(_ => _.valueOf() !== newDate.valueOf())
|
||||
: coerceTruthyValueToArray(props.parsedValue).concat([newDate])
|
||||
ctx.emit('pick', newValue)
|
||||
}
|
||||
}
|
||||
|
||||
const isWeekActive = cell => {
|
||||
if (props.selectionMode !== 'week') return false
|
||||
let newDate = props.date.startOf('day')
|
||||
|
||||
if (cell.type === 'prev-month') {
|
||||
newDate = newDate.subtract(1, 'month')
|
||||
}
|
||||
|
||||
if (cell.type === 'next-month') {
|
||||
newDate = newDate.add(1, 'month')
|
||||
}
|
||||
|
||||
newDate = newDate.date(parseInt(cell.text, 10))
|
||||
|
||||
if (props.parsedValue && !Array.isArray(props.parsedValue)) {
|
||||
const dayOffset = (props.parsedValue.day() - firstDayOfWeek + 7) % 7 - 1
|
||||
const weekDate = props.parsedValue.subtract(dayOffset, 'day')
|
||||
return weekDate.isSame(newDate, 'day')
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return {
|
||||
handleMouseMove,
|
||||
t,
|
||||
rows,
|
||||
isWeekActive,
|
||||
getCellClasses,
|
||||
WEEKS,
|
||||
handleClick,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
222
packages/date-picker/src/date-picker-com/basic-month-table.vue
Normal file
222
packages/date-picker/src/date-picker-com/basic-month-table.vue
Normal file
@ -0,0 +1,222 @@
|
||||
<template>
|
||||
<table class="el-month-table" @click="handleMonthTableClick" @mousemove="handleMouseMove">
|
||||
<tbody>
|
||||
<tr v-for="(row, key) in rows" :key="key">
|
||||
<td v-for="(cell, key_) in row" :key="key_" :class="getCellStyle(cell)">
|
||||
<div>
|
||||
<a class="cell">{{ t('el.datepicker.months.' + months[cell.text]) }}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { hasClass } from '@element-plus/utils/dom'
|
||||
import { coerceTruthyValueToArray } from '@element-plus/utils/util'
|
||||
import { rangeArr } from '@element-plus/time-picker/src/common/date-utils'
|
||||
import { t } from '@element-plus/locale'
|
||||
import dayjs, { Dayjs } from 'dayjs'
|
||||
|
||||
import {
|
||||
defineComponent,
|
||||
computed,
|
||||
ref,
|
||||
PropType,
|
||||
} from 'vue'
|
||||
|
||||
const datesInMonth = (year, month) => {
|
||||
const firstDay = dayjs().startOf('month').month(month).year(year)
|
||||
const numOfDays = firstDay.daysInMonth()
|
||||
return rangeArr(numOfDays).map(n => firstDay.add(n, 'day').toDate())
|
||||
}
|
||||
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
disabledDate: {
|
||||
type: Function as PropType<(_: Date) => void>,
|
||||
},
|
||||
selectionMode: {
|
||||
type: String,
|
||||
default: 'month',
|
||||
},
|
||||
minDate: {
|
||||
type: Dayjs as PropType<Dayjs>,
|
||||
},
|
||||
maxDate: {
|
||||
type: Dayjs as PropType<Dayjs>,
|
||||
},
|
||||
date: {
|
||||
type: Dayjs as PropType<Dayjs>,
|
||||
},
|
||||
parsedValue: {
|
||||
type: Dayjs as PropType<Dayjs>,
|
||||
},
|
||||
rangeState: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
endDate: null,
|
||||
selecting: false,
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['changerange', 'pick', 'select'],
|
||||
|
||||
setup(props, ctx) {
|
||||
const months = ref(props.date.locale('en').localeData().monthsShort().map(_=>_.toLowerCase()))
|
||||
const tableRows = ref([ [], [], [] ])
|
||||
const lastRow = ref(null)
|
||||
const lastColumn = ref(null)
|
||||
const rows = computed(() =>{
|
||||
// TODO: refactory rows / getCellClasses
|
||||
const rows = tableRows.value
|
||||
const now = dayjs().startOf('month')
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const row = rows[i]
|
||||
for (let j = 0; j < 4; j++) {
|
||||
let cell = row[j]
|
||||
if (!cell) {
|
||||
cell = {
|
||||
row: i,
|
||||
column: j,
|
||||
type: 'normal',
|
||||
inRange: false,
|
||||
start: false,
|
||||
end: false,
|
||||
}
|
||||
}
|
||||
|
||||
cell.type = 'normal'
|
||||
|
||||
const index = i * 4 + j
|
||||
const calTime = props.date.startOf('year').month(index)
|
||||
|
||||
const calEndDate = props.rangeState.endDate || props.maxDate
|
||||
|| props.rangeState.selecting && props.minDate
|
||||
|
||||
cell.inRange = (
|
||||
props.minDate &&
|
||||
calTime.isSameOrAfter(props.minDate, 'month')
|
||||
&& (
|
||||
calEndDate &&
|
||||
calTime.isSameOrBefore(calEndDate, 'month')
|
||||
))
|
||||
|
||||
cell.start = props.minDate && calTime.isSame(props.minDate, 'month')
|
||||
|
||||
cell.end = calEndDate && calTime.isSame(calEndDate, 'month')
|
||||
|
||||
const isToday = now.isSame(calTime)
|
||||
|
||||
if (isToday) {
|
||||
cell.type = 'today'
|
||||
}
|
||||
cell.text = index
|
||||
let cellDate = calTime.toDate()
|
||||
cell.disabled = props.disabledDate && props.disabledDate(cellDate)
|
||||
row[j] = cell
|
||||
}
|
||||
}
|
||||
return rows
|
||||
})
|
||||
const getCellStyle = cell => {
|
||||
const style = {} as any
|
||||
const year = props.date.year()
|
||||
const today = new Date()
|
||||
const month = cell.text
|
||||
|
||||
style.disabled = props.disabledDate
|
||||
? datesInMonth(year, month).every(props.disabledDate)
|
||||
: false
|
||||
style.current = coerceTruthyValueToArray(props.parsedValue).findIndex(date => date.year() === year && date.month() === month) >= 0
|
||||
style.today = today.getFullYear() === year && today.getMonth() === month
|
||||
|
||||
if (cell.inRange) {
|
||||
style['in-range'] = true
|
||||
|
||||
if (cell.start) {
|
||||
style['start-date'] = true
|
||||
}
|
||||
|
||||
if (cell.end) {
|
||||
style['end-date'] = true
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
const handleMouseMove = event => {
|
||||
if (!props.rangeState.selecting) return
|
||||
|
||||
let target = event.target
|
||||
if (target.tagName === 'A') {
|
||||
target = target.parentNode.parentNode
|
||||
}
|
||||
if (target.tagName === 'DIV') {
|
||||
target = target.parentNode
|
||||
}
|
||||
if (target.tagName !== 'TD') return
|
||||
|
||||
const row = target.parentNode.rowIndex
|
||||
const column = target.cellIndex
|
||||
// can not select disabled date
|
||||
if (rows.value[row][column].disabled) return
|
||||
|
||||
// only update rangeState when mouse moves to a new cell
|
||||
// this avoids frequent Date object creation and improves performance
|
||||
if (row !== lastRow.value || column !== lastColumn.value) {
|
||||
lastRow.value = row
|
||||
lastColumn.value = column
|
||||
ctx.emit('changerange', {
|
||||
selecting: true,
|
||||
endDate: props.date.startOf('year').month(row * 4 + column),
|
||||
})
|
||||
}
|
||||
}
|
||||
const handleMonthTableClick = event => {
|
||||
let target = event.target
|
||||
if (target.tagName === 'A') {
|
||||
target = target.parentNode.parentNode
|
||||
}
|
||||
if (target.tagName === 'DIV') {
|
||||
target = target.parentNode
|
||||
}
|
||||
if (target.tagName !== 'TD') return
|
||||
if (hasClass(target, 'disabled')) return
|
||||
const column = target.cellIndex
|
||||
const row = target.parentNode.rowIndex
|
||||
const month = row * 4 + column
|
||||
const newDate = props.date.startOf('year').month(month)
|
||||
if (props.selectionMode === 'range') {
|
||||
if (!props.rangeState.selecting) {
|
||||
ctx.emit('pick', { minDate: newDate, maxDate: null })
|
||||
ctx.emit('select', true)
|
||||
} else {
|
||||
if (newDate >= props.minDate) {
|
||||
ctx.emit('pick', { minDate: props.minDate, maxDate: newDate })
|
||||
} else {
|
||||
ctx.emit('pick', { minDate: newDate, maxDate: props.minDate })
|
||||
}
|
||||
ctx.emit('select', false)
|
||||
}
|
||||
} else {
|
||||
ctx.emit('pick', month)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
handleMouseMove,
|
||||
handleMonthTableClick,
|
||||
rows,
|
||||
getCellStyle,
|
||||
t,
|
||||
months,
|
||||
}
|
||||
},
|
||||
|
||||
})
|
||||
</script>
|
112
packages/date-picker/src/date-picker-com/basic-year-table.vue
Normal file
112
packages/date-picker/src/date-picker-com/basic-year-table.vue
Normal file
@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<table class="el-year-table" @click="handleYearTableClick">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="available" :class="getCellStyle(startYear + 0)">
|
||||
<a class="cell">{{ startYear }}</a>
|
||||
</td>
|
||||
<td class="available" :class="getCellStyle(startYear + 1)">
|
||||
<a class="cell">{{ startYear + 1 }}</a>
|
||||
</td>
|
||||
<td class="available" :class="getCellStyle(startYear + 2)">
|
||||
<a class="cell">{{ startYear + 2 }}</a>
|
||||
</td>
|
||||
<td class="available" :class="getCellStyle(startYear + 3)">
|
||||
<a class="cell">{{ startYear + 3 }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="available" :class="getCellStyle(startYear + 4)">
|
||||
<a class="cell">{{ startYear + 4 }}</a>
|
||||
</td>
|
||||
<td class="available" :class="getCellStyle(startYear + 5)">
|
||||
<a class="cell">{{ startYear + 5 }}</a>
|
||||
</td>
|
||||
<td class="available" :class="getCellStyle(startYear + 6)">
|
||||
<a class="cell">{{ startYear + 6 }}</a>
|
||||
</td>
|
||||
<td class="available" :class="getCellStyle(startYear + 7)">
|
||||
<a class="cell">{{ startYear + 7 }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="available" :class="getCellStyle(startYear + 8)">
|
||||
<a class="cell">{{ startYear + 8 }}</a>
|
||||
</td>
|
||||
<td class="available" :class="getCellStyle(startYear + 9)">
|
||||
<a class="cell">{{ startYear + 9 }}</a>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { hasClass } from '@element-plus/utils/dom'
|
||||
import { rangeArr } from '@element-plus/time-picker/src/common/date-utils'
|
||||
import { coerceTruthyValueToArray } from '@element-plus/utils/util'
|
||||
import {
|
||||
defineComponent,
|
||||
computed,
|
||||
PropType,
|
||||
} from 'vue'
|
||||
import dayjs, { Dayjs } from 'dayjs'
|
||||
|
||||
const datesInYear = year => {
|
||||
const firstDay = dayjs().startOf('year')
|
||||
const numOfDays = dayjs(year).isLeapYear() ? 366 : 365
|
||||
return rangeArr(numOfDays).map(n => firstDay.add(n, 'day').toDate())
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
disabledDate: {
|
||||
type: Function as PropType<(_: Date) => void>,
|
||||
},
|
||||
parsedValue: {
|
||||
type: Dayjs as PropType<Dayjs>,
|
||||
},
|
||||
date: {
|
||||
type: Dayjs as PropType<Dayjs>,
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['pick'],
|
||||
|
||||
setup(props, ctx) {
|
||||
const startYear = computed(() =>{
|
||||
return Math.floor(props.date.year() / 10) * 10
|
||||
})
|
||||
const getCellStyle = year => {
|
||||
const style = {} as any
|
||||
const today = dayjs()
|
||||
|
||||
style.disabled = props.disabledDate
|
||||
? datesInYear(year).every(props.disabledDate)
|
||||
: false
|
||||
|
||||
style.current = coerceTruthyValueToArray(props.parsedValue).findIndex(_ => _.year() === year) >= 0
|
||||
|
||||
style.today = today.year() === year
|
||||
|
||||
return style
|
||||
}
|
||||
|
||||
const handleYearTableClick = event => {
|
||||
const target = event.target
|
||||
if (target.tagName === 'A') {
|
||||
if (hasClass(target.parentNode, 'disabled')) return
|
||||
const year = target.textContent || target.innerText
|
||||
ctx.emit('pick', Number(year))
|
||||
}
|
||||
}
|
||||
return {
|
||||
startYear,
|
||||
getCellStyle,
|
||||
handleYearTableClick,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
585
packages/date-picker/src/date-picker-com/panel-date-pick.vue
Normal file
585
packages/date-picker/src/date-picker-com/panel-date-pick.vue
Normal file
@ -0,0 +1,585 @@
|
||||
<template>
|
||||
<transition name="el-zoom-in-top">
|
||||
<div
|
||||
v-if="visible"
|
||||
class="el-picker-panel el-date-picker"
|
||||
:class="[{
|
||||
'has-sidebar': $slots.sidebar || hasShortcuts,
|
||||
'has-time': showTime
|
||||
}]"
|
||||
>
|
||||
<div class="el-picker-panel__body-wrapper">
|
||||
<slot name="sidebar" class="el-picker-panel__sidebar"></slot>
|
||||
<div v-if="hasShortcuts" class="el-picker-panel__sidebar">
|
||||
<button
|
||||
v-for="(shortcut, key) in shortcuts"
|
||||
:key="key"
|
||||
type="button"
|
||||
class="el-picker-panel__shortcut"
|
||||
@click="handleShortcutClick(shortcut)"
|
||||
>
|
||||
{{ shortcut.text }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="el-picker-panel__body">
|
||||
<div v-if="showTime" class="el-date-picker__time-header">
|
||||
<span class="el-date-picker__editor-wrap">
|
||||
<el-input
|
||||
:placeholder="t('el.datepicker.selectDate')"
|
||||
:model-value="visibleDate"
|
||||
size="small"
|
||||
@input="val => userInputDate = val"
|
||||
@change="handleVisibleDateChange"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
v-clickoutside="handleTimePickClose"
|
||||
class="el-date-picker__editor-wrap"
|
||||
>
|
||||
<el-input
|
||||
:placeholder="t('el.datepicker.selectTime')"
|
||||
:model-value="visibleTime"
|
||||
size="small"
|
||||
@focus="onTimePickerInputFocus"
|
||||
@input="val => userInputTime = val"
|
||||
@change="handleVisibleTimeChange"
|
||||
/>
|
||||
<time-pick-panel
|
||||
:visible="timePickerVisible"
|
||||
:format="timeFormat"
|
||||
:time-arrow-control="arrowControl"
|
||||
:parsed-value="innerDate"
|
||||
@pick="handleTimePick"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-show="currentView !== 'time'"
|
||||
class="el-date-picker__header"
|
||||
:class="{ 'el-date-picker__header--bordered': currentView === 'year' || currentView === 'month' }"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
:aria-label="t(`el.datepicker.prevYear`)"
|
||||
class="el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-d-arrow-left"
|
||||
@click="prevYear_"
|
||||
>
|
||||
</button>
|
||||
<button
|
||||
v-show="currentView === 'date'"
|
||||
type="button"
|
||||
:aria-label="t(`el.datepicker.prevMonth`)"
|
||||
class="el-picker-panel__icon-btn el-date-picker__prev-btn el-icon-arrow-left"
|
||||
@click="prevMonth_"
|
||||
>
|
||||
</button>
|
||||
<span
|
||||
role="button"
|
||||
class="el-date-picker__header-label"
|
||||
@click="showYearPicker"
|
||||
>{{ yearLabel }}</span>
|
||||
<span
|
||||
v-show="currentView === 'date'"
|
||||
role="button"
|
||||
class="el-date-picker__header-label"
|
||||
:class="{ active: currentView === 'month' }"
|
||||
@click="showMonthPicker"
|
||||
>{{ t(`el.datepicker.month${ month + 1 }`) }}</span>
|
||||
<button
|
||||
type="button"
|
||||
:aria-label="t(`el.datepicker.nextYear`)"
|
||||
class="el-picker-panel__icon-btn el-date-picker__next-btn el-icon-d-arrow-right"
|
||||
@click="nextYear_"
|
||||
>
|
||||
</button>
|
||||
<button
|
||||
v-show="currentView === 'date'"
|
||||
type="button"
|
||||
:aria-label="t(`el.datepicker.nextMonth`)"
|
||||
class="el-picker-panel__icon-btn el-date-picker__next-btn el-icon-arrow-right"
|
||||
@click="nextMonth_"
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="el-picker-panel__content">
|
||||
<date-table
|
||||
v-if="currentView === 'date'"
|
||||
:selection-mode="selectionMode"
|
||||
:date="innerDate"
|
||||
:parsed-value="parsedValue"
|
||||
:disabled-date="disabledDate"
|
||||
@pick="handleDatePick"
|
||||
/>
|
||||
<year-table
|
||||
v-if="currentView === 'year'"
|
||||
:date="innerDate"
|
||||
:disabled-date="disabledDate"
|
||||
:parsed-value="parsedValue"
|
||||
@pick="handleYearPick"
|
||||
/>
|
||||
<month-table
|
||||
v-if="currentView === 'month'"
|
||||
:date="innerDate"
|
||||
:parsed-value="parsedValue"
|
||||
:disabled-date="disabledDate"
|
||||
@pick="handleMonthPick"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-show="footerVisible && currentView === 'date'"
|
||||
class="el-picker-panel__footer"
|
||||
>
|
||||
<el-button
|
||||
v-show="selectionMode !== 'dates'"
|
||||
size="mini"
|
||||
type="text"
|
||||
class="el-picker-panel__link-btn"
|
||||
@click="changeToNow"
|
||||
>
|
||||
{{ t('el.datepicker.now') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
size="mini"
|
||||
class="el-picker-panel__link-btn"
|
||||
@click="onConfirm"
|
||||
>
|
||||
{{ t('el.datepicker.confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {
|
||||
extractDateFormat,
|
||||
extractTimeFormat,
|
||||
} from '@element-plus/time-picker/src/common/date-utils'
|
||||
import { t } from '@element-plus/locale'
|
||||
import ElInput from '@element-plus/input/src/index.vue'
|
||||
import { ClickOutside } from '@element-plus/directives'
|
||||
import { EVENT_CODE } from '@element-plus/utils/aria'
|
||||
import { Button as ElButton } from '@element-plus/button'
|
||||
import dayjs, { Dayjs } from 'dayjs'
|
||||
import DateTable from './basic-date-table.vue'
|
||||
import MonthTable from './basic-month-table.vue'
|
||||
import YearTable from './basic-year-table.vue'
|
||||
import TimePickPanel from '@element-plus/time-picker/src/time-picker-com/panel-time-pick.vue'
|
||||
import {
|
||||
defineComponent,
|
||||
computed,
|
||||
ref,
|
||||
PropType,
|
||||
watch,
|
||||
inject,
|
||||
} from 'vue'
|
||||
|
||||
// todo
|
||||
const timeWithinRange = () => true
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
DateTable, ElInput, ElButton, TimePickPanel, MonthTable, YearTable,
|
||||
},
|
||||
|
||||
directives: { clickoutside: ClickOutside },
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
parsedValue: {
|
||||
type: [Object, Array] as PropType<Dayjs | Dayjs[]>,
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
emits: ['pick', 'set-picker-option'],
|
||||
setup(props, ctx) {
|
||||
const innerDate = ref(dayjs())
|
||||
|
||||
const month = computed(() => {
|
||||
return innerDate.value.month()
|
||||
})
|
||||
|
||||
const year = computed(() => {
|
||||
return innerDate.value.year()
|
||||
})
|
||||
|
||||
const selectableRange = ref([])
|
||||
const userInputDate = ref(null)
|
||||
const userInputTime = ref(null)
|
||||
// todo update to disableHour
|
||||
const checkDateWithinRange = date => {
|
||||
return selectableRange.value.length > 0
|
||||
? timeWithinRange(date, selectableRange.value, props.format || 'HH:mm:ss')
|
||||
: true
|
||||
}
|
||||
const formatEmit = (emitDayjs: Dayjs) => {
|
||||
if (showTime.value) return emitDayjs.millisecond(0)
|
||||
if (defaultTime) {
|
||||
const defaultTimeD = dayjs(defaultTime)
|
||||
return defaultTimeD.year(emitDayjs.year()).month(emitDayjs.month()).date(emitDayjs.date())
|
||||
}
|
||||
return emitDayjs.startOf('day')
|
||||
}
|
||||
const emit = (value, ...args) => {
|
||||
if (!value) {
|
||||
ctx.emit('pick', value, ...args)
|
||||
} else if (Array.isArray(value)) {
|
||||
const dates = value.map(formatEmit)
|
||||
ctx.emit('pick', dates, ...args)
|
||||
} else {
|
||||
ctx.emit('pick', formatEmit(value), ...args)
|
||||
}
|
||||
userInputDate.value = null
|
||||
userInputTime.value = null
|
||||
}
|
||||
const handleDatePick = (value: Dayjs) => {
|
||||
if (selectionMode.value === 'day') {
|
||||
let newDate = props.parsedValue ? (props.parsedValue as Dayjs).year(value.year()).month(value.month()).date(value.date()) : value
|
||||
// change default time while out of selectableRange
|
||||
if (!checkDateWithinRange(newDate)) {
|
||||
newDate = (selectableRange.value[0][0] as Dayjs).year(value.year()).month(value.month()).date(value.date())
|
||||
}
|
||||
innerDate.value = newDate
|
||||
emit(newDate, showTime.value)
|
||||
} else if (selectionMode.value === 'week') {
|
||||
emit(value.date)
|
||||
} else if (selectionMode.value === 'dates') {
|
||||
emit(value, true) // set false to keep panel open
|
||||
}
|
||||
}
|
||||
const prevMonth_ = () => {
|
||||
innerDate.value = innerDate.value.subtract(1, 'month')
|
||||
}
|
||||
|
||||
const nextMonth_ = () => {
|
||||
innerDate.value = innerDate.value.add(1, 'month')
|
||||
}
|
||||
|
||||
const prevYear_ = () => {
|
||||
if (currentView.value === 'year') {
|
||||
innerDate.value = innerDate.value.subtract(10, 'year')
|
||||
} else {
|
||||
innerDate.value = innerDate.value.subtract(1, 'year')
|
||||
}
|
||||
}
|
||||
|
||||
const nextYear_ = () => {
|
||||
if (currentView.value === 'year') {
|
||||
innerDate.value = innerDate.value.add(10, 'year')
|
||||
} else {
|
||||
innerDate.value = innerDate.value.add(1, 'year')
|
||||
}
|
||||
}
|
||||
|
||||
const currentView = ref('date')
|
||||
|
||||
const yearLabel = computed(() => {
|
||||
const yearTranslation = t('el.datepicker.year')
|
||||
if (currentView.value === 'year') {
|
||||
const startYear = Math.floor(year.value / 10) * 10
|
||||
if (yearTranslation) {
|
||||
return startYear + ' ' + yearTranslation + ' - ' + (startYear + 9) + ' ' + yearTranslation
|
||||
}
|
||||
return startYear + ' - ' + (startYear + 9)
|
||||
}
|
||||
return year.value + ' ' + yearTranslation
|
||||
})
|
||||
|
||||
const handleShortcutClick = shortcut => {
|
||||
if (shortcut.value) {
|
||||
emit(dayjs(shortcut.value))
|
||||
return
|
||||
}
|
||||
if (shortcut.onClick) {
|
||||
shortcut.onClick(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
const selectionMode = computed(() => {
|
||||
if (['week', 'month', 'year', 'dates'].includes(props.type)) {
|
||||
return props.type
|
||||
}
|
||||
return 'day'
|
||||
})
|
||||
|
||||
watch(() => selectionMode.value, val => {
|
||||
if(['month', 'year'].includes(val)) {
|
||||
currentView.value = val
|
||||
return
|
||||
}
|
||||
currentView.value = 'date'
|
||||
}, { immediate: true })
|
||||
|
||||
const hasShortcuts = computed(() => !!shortcuts.length)
|
||||
|
||||
const handleMonthPick = month => {
|
||||
innerDate.value = innerDate.value.startOf('month').month(month)
|
||||
if (selectionMode.value === 'month') {
|
||||
emit(innerDate.value)
|
||||
} else {
|
||||
currentView.value = 'date'
|
||||
}
|
||||
}
|
||||
|
||||
const handleYearPick = year => {
|
||||
if (selectionMode.value === 'year') {
|
||||
innerDate.value = innerDate.value.startOf('year').year(year)
|
||||
emit(innerDate.value)
|
||||
}
|
||||
else {
|
||||
innerDate.value = innerDate.value.year(year)
|
||||
currentView.value = 'month'
|
||||
}
|
||||
}
|
||||
|
||||
const showMonthPicker = () => {
|
||||
currentView.value = 'month'
|
||||
}
|
||||
|
||||
const showYearPicker = () => {
|
||||
currentView.value = 'year'
|
||||
}
|
||||
|
||||
const showTime = computed(() => props.type === 'datetime' || props.type === 'datetimerange')
|
||||
|
||||
const footerVisible = computed(() => {
|
||||
return showTime.value || selectionMode.value === 'dates'
|
||||
})
|
||||
|
||||
const onConfirm = () => {
|
||||
if (selectionMode.value === 'dates') {
|
||||
emit(props.parsedValue)
|
||||
} else {
|
||||
// deal with the scenario where: user opens the date time picker, then confirm without doing anything
|
||||
let result = props.parsedValue as Dayjs
|
||||
if (!result) {
|
||||
const defaultTimeD = dayjs(defaultTime)
|
||||
const defaultValueD = getDefaultValue()
|
||||
result = defaultTimeD.year(defaultValueD.year()).month(defaultValueD.month()).date(defaultValueD.date())
|
||||
}
|
||||
innerDate.value = result
|
||||
emit(result)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const changeToNow = () => {
|
||||
// NOTE: not a permanent solution
|
||||
// consider disable "now" button in the future
|
||||
const now = dayjs()
|
||||
const nowDate = now.toDate()
|
||||
if ((!disabledDate || !disabledDate(nowDate)) && checkDateWithinRange(nowDate)) {
|
||||
innerDate.value = dayjs()
|
||||
emit(innerDate.value)
|
||||
}
|
||||
}
|
||||
|
||||
const timeFormat = computed(() => {
|
||||
return extractTimeFormat(props.format)
|
||||
})
|
||||
|
||||
const dateFormat = computed(() => {
|
||||
return extractDateFormat(props.format)
|
||||
})
|
||||
|
||||
const visibleTime = computed(() => {
|
||||
if (userInputTime.value) return userInputTime.value
|
||||
if (!props.parsedValue && !defaultValue) return
|
||||
return ((props.parsedValue || innerDate.value) as Dayjs).format(timeFormat.value)
|
||||
})
|
||||
|
||||
const visibleDate = computed(() => {
|
||||
if (userInputDate.value) return userInputDate.value
|
||||
if (!props.parsedValue && !defaultValue) return
|
||||
return ((props.parsedValue || innerDate.value) as Dayjs).format(dateFormat.value)
|
||||
})
|
||||
|
||||
const timePickerVisible = ref(false)
|
||||
const onTimePickerInputFocus = () => {
|
||||
timePickerVisible.value = true
|
||||
}
|
||||
const handleTimePickClose = () => {
|
||||
timePickerVisible.value = false
|
||||
}
|
||||
|
||||
const handleTimePick = (value, visible, first) => {
|
||||
const newDate = props.parsedValue ? (props.parsedValue as Dayjs).hour(value.hour()).minute(value.minute()).second(value.second()) : value
|
||||
innerDate.value = newDate
|
||||
emit(innerDate.value, true)
|
||||
if (!first) {
|
||||
timePickerVisible.value = visible
|
||||
}
|
||||
}
|
||||
|
||||
const handleVisibleTimeChange = value => {
|
||||
const newDate = dayjs(value, timeFormat.value)
|
||||
if (newDate.isValid() && checkDateWithinRange(newDate)) {
|
||||
innerDate.value = newDate.year(innerDate.value.year()).month(innerDate.value.month()).date(innerDate.value.date())
|
||||
userInputTime.value = null
|
||||
timePickerVisible.value = false
|
||||
emit(innerDate.value, true)
|
||||
}
|
||||
}
|
||||
|
||||
const handleVisibleDateChange = value => {
|
||||
const newDate = dayjs(value, dateFormat.value)
|
||||
if (newDate.isValid()) {
|
||||
if (disabledDate && disabledDate(newDate.toDate())) {
|
||||
return
|
||||
}
|
||||
innerDate.value = newDate.hour(innerDate.value.hour()).minute(innerDate.value.minute()).second(innerDate.value.second())
|
||||
userInputDate.value = null
|
||||
emit(innerDate.value, true)
|
||||
}
|
||||
}
|
||||
|
||||
const isValidValue = date_ => {
|
||||
return date_.isValid() && (
|
||||
disabledDate
|
||||
? !disabledDate(date_.toDate())
|
||||
: true
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
const formatToString = value => {
|
||||
if (selectionMode.value === 'dates') {
|
||||
return value.map(_ => _.format(props.format))
|
||||
}
|
||||
return value.format(props.format)
|
||||
}
|
||||
|
||||
const parseUserInput = value => {
|
||||
return dayjs(value, props.format)
|
||||
}
|
||||
|
||||
const getDefaultValue = () => {
|
||||
return dayjs(defaultValue)
|
||||
}
|
||||
|
||||
const handleKeydown = event => {
|
||||
const { code, keyCode } = event
|
||||
const list = [EVENT_CODE.up, EVENT_CODE.down, EVENT_CODE.left, EVENT_CODE.right]
|
||||
if (props.visible && !timePickerVisible.value) {
|
||||
if (list.includes(code)) {
|
||||
handleKeyControl(keyCode)
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
if (code === EVENT_CODE.enter
|
||||
&& userInputDate.value === null
|
||||
&& userInputTime.value === null
|
||||
) { // Enter
|
||||
emit(innerDate, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyControl = keyCode => {
|
||||
const mapping = {
|
||||
'year': {
|
||||
38: -4, 40: 4, 37: -1, 39: 1, offset: (date, step) => date.setFullYear(date.getFullYear() + step),
|
||||
},
|
||||
'month': {
|
||||
38: -4, 40: 4, 37: -1, 39: 1, offset: (date, step) => date.setMonth(date.getMonth() + step),
|
||||
},
|
||||
'week': {
|
||||
38: -1, 40: 1, 37: -1, 39: 1, offset: (date, step) => date.setDate(date.getDate() + step * 7),
|
||||
},
|
||||
'day': {
|
||||
38: -7, 40: 7, 37: -1, 39: 1, offset: (date, step) => date.setDate(date.getDate() + step),
|
||||
},
|
||||
}
|
||||
|
||||
const newDate = innerDate.value.toDate()
|
||||
while (Math.abs(innerDate.value.diff(newDate, 'year', true)) < 1) {
|
||||
const map = mapping[selectionMode.value]
|
||||
map.offset(newDate, map[keyCode])
|
||||
if (disabledDate && disabledDate(newDate)) {
|
||||
continue
|
||||
}
|
||||
const result = dayjs(newDate)
|
||||
innerDate.value = result
|
||||
ctx.emit('pick', result, true)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
ctx.emit('set-picker-option', ['isValidValue', isValidValue])
|
||||
ctx.emit('set-picker-option', ['formatToString', formatToString])
|
||||
ctx.emit('set-picker-option', ['parseUserInput', parseUserInput])
|
||||
ctx.emit('set-picker-option',['handleKeydown', handleKeydown])
|
||||
|
||||
const pickerBase = inject('EP_PICKER_BASE') as any
|
||||
const { shortcuts, disabledDate, cellClassName, defaultTime, defaultValue, arrowControl } = pickerBase.props
|
||||
|
||||
watch(() => props.parsedValue, val => {
|
||||
if (val) {
|
||||
if (selectionMode.value === 'dates') return
|
||||
if (Array.isArray(val)) return
|
||||
innerDate.value = val
|
||||
} else {
|
||||
innerDate.value = getDefaultValue()
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
return {
|
||||
handleTimePick,
|
||||
handleTimePickClose,
|
||||
onTimePickerInputFocus,
|
||||
timePickerVisible,
|
||||
visibleTime,
|
||||
visibleDate,
|
||||
showTime,
|
||||
changeToNow,
|
||||
onConfirm,
|
||||
footerVisible,
|
||||
handleYearPick,
|
||||
showMonthPicker,
|
||||
showYearPicker,
|
||||
handleMonthPick,
|
||||
hasShortcuts,
|
||||
shortcuts,
|
||||
arrowControl,
|
||||
disabledDate,
|
||||
cellClassName,
|
||||
selectionMode,
|
||||
handleShortcutClick,
|
||||
prevYear_,
|
||||
nextYear_,
|
||||
prevMonth_,
|
||||
nextMonth_,
|
||||
innerDate,
|
||||
t,
|
||||
yearLabel,
|
||||
currentView,
|
||||
month,
|
||||
handleDatePick,
|
||||
handleVisibleTimeChange,
|
||||
handleVisibleDateChange,
|
||||
timeFormat,
|
||||
userInputTime,
|
||||
userInputDate,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
.el-time-panel {
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
666
packages/date-picker/src/date-picker-com/panel-date-range.vue
Normal file
666
packages/date-picker/src/date-picker-com/panel-date-range.vue
Normal file
@ -0,0 +1,666 @@
|
||||
<template>
|
||||
<transition name="el-zoom-in-top">
|
||||
<div
|
||||
class="el-picker-panel el-date-range-picker"
|
||||
:class="[{
|
||||
'has-sidebar': $slots.sidebar || hasShortcuts,
|
||||
'has-time': showTime
|
||||
}]"
|
||||
>
|
||||
<div class="el-picker-panel__body-wrapper">
|
||||
<slot name="sidebar" class="el-picker-panel__sidebar"></slot>
|
||||
<div v-if="hasShortcuts" class="el-picker-panel__sidebar">
|
||||
<button
|
||||
v-for="(shortcut, key) in shortcuts"
|
||||
:key="key"
|
||||
type="button"
|
||||
class="el-picker-panel__shortcut"
|
||||
@click="handleShortcutClick(shortcut)"
|
||||
>
|
||||
{{ shortcut.text }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="el-picker-panel__body">
|
||||
<div v-if="showTime" class="el-date-range-picker__time-header">
|
||||
<span class="el-date-range-picker__editors-wrap">
|
||||
<span class="el-date-range-picker__time-picker-wrap">
|
||||
<el-input
|
||||
size="small"
|
||||
:disabled="rangeState.selecting"
|
||||
:placeholder="t('el.datepicker.startDate')"
|
||||
class="el-date-range-picker__editor"
|
||||
:model-value="minVisibleDate"
|
||||
@input="val => handleDateInput(val, 'min')"
|
||||
@change="val => handleDateChange(val, 'min')"
|
||||
/>
|
||||
</span>
|
||||
<span v-clickoutside="handleMinTimeClose" class="el-date-range-picker__time-picker-wrap">
|
||||
<el-input
|
||||
size="small"
|
||||
class="el-date-range-picker__editor"
|
||||
:disabled="rangeState.selecting"
|
||||
:placeholder="t('el.datepicker.startTime')"
|
||||
:model-value="minVisibleTime"
|
||||
@focus="minTimePickerVisible = true"
|
||||
@input="val => handleTimeInput(val, 'min')"
|
||||
@change="val => handleTimeChange(val, 'min')"
|
||||
/>
|
||||
<time-pick-panel
|
||||
:visible="minTimePickerVisible"
|
||||
:format="timeFormat"
|
||||
datetime-role="start"
|
||||
:time-arrow-control="arrowControl"
|
||||
:parsed-value="leftDate"
|
||||
@pick="handleMinTimePick"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
<span class="el-icon-arrow-right"></span>
|
||||
<span class="el-date-range-picker__editors-wrap is-right">
|
||||
<span class="el-date-range-picker__time-picker-wrap">
|
||||
<el-input
|
||||
size="small"
|
||||
class="el-date-range-picker__editor"
|
||||
:disabled="rangeState.selecting"
|
||||
:placeholder="t('el.datepicker.endDate')"
|
||||
:model-value="maxVisibleDate"
|
||||
:readonly="!minDate"
|
||||
@input="val => handleDateInput(val, 'max')"
|
||||
@change="val => handleDateChange(val, 'max')"
|
||||
/>
|
||||
</span>
|
||||
<span v-clickoutside="handleMaxTimeClose" class="el-date-range-picker__time-picker-wrap">
|
||||
<el-input
|
||||
size="small"
|
||||
class="el-date-range-picker__editor"
|
||||
:disabled="rangeState.selecting"
|
||||
:placeholder="t('el.datepicker.endTime')"
|
||||
:model-value="maxVisibleTime"
|
||||
:readonly="!minDate"
|
||||
@focus="minDate && (maxTimePickerVisible = true)"
|
||||
@input="val => handleTimeInput(val, 'max')"
|
||||
@change="val => handleTimeChange(val, 'max')"
|
||||
/>
|
||||
<time-pick-panel
|
||||
datetime-role="end"
|
||||
:visible="maxTimePickerVisible"
|
||||
:format="timeFormat"
|
||||
:time-arrow-control="arrowControl"
|
||||
:parsed-value="rightDate"
|
||||
@pick="handleMaxTimePick"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="el-picker-panel__content el-date-range-picker__content is-left">
|
||||
<div class="el-date-range-picker__header">
|
||||
<button
|
||||
type="button"
|
||||
class="el-picker-panel__icon-btn el-icon-d-arrow-left"
|
||||
@click="leftPrevYear"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
class="el-picker-panel__icon-btn el-icon-arrow-left"
|
||||
@click="leftPrevMonth"
|
||||
></button>
|
||||
<button
|
||||
v-if="unlinkPanels"
|
||||
type="button"
|
||||
:disabled="!enableYearArrow"
|
||||
:class="{ 'is-disabled': !enableYearArrow }"
|
||||
class="el-picker-panel__icon-btn el-icon-d-arrow-right"
|
||||
@click="leftNextYear"
|
||||
></button>
|
||||
<button
|
||||
v-if="unlinkPanels"
|
||||
type="button"
|
||||
:disabled="!enableMonthArrow"
|
||||
:class="{ 'is-disabled': !enableMonthArrow }"
|
||||
class="el-picker-panel__icon-btn el-icon-arrow-right"
|
||||
@click="leftNextMonth"
|
||||
></button>
|
||||
<div>{{ leftLabel }}</div>
|
||||
</div>
|
||||
<date-table
|
||||
selection-mode="range"
|
||||
:date="leftDate"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
:range-state="rangeState"
|
||||
:disabled-date="disabledDate"
|
||||
:cell-class-name="cellClassName"
|
||||
@changerange="handleChangeRange"
|
||||
@pick="handleRangePick"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</div>
|
||||
<div class="el-picker-panel__content el-date-range-picker__content is-right">
|
||||
<div class="el-date-range-picker__header">
|
||||
<button
|
||||
v-if="unlinkPanels"
|
||||
type="button"
|
||||
:disabled="!enableYearArrow"
|
||||
:class="{ 'is-disabled': !enableYearArrow }"
|
||||
class="el-picker-panel__icon-btn el-icon-d-arrow-left"
|
||||
@click="rightPrevYear"
|
||||
></button>
|
||||
<button
|
||||
v-if="unlinkPanels"
|
||||
type="button"
|
||||
:disabled="!enableMonthArrow"
|
||||
:class="{ 'is-disabled': !enableMonthArrow }"
|
||||
class="el-picker-panel__icon-btn el-icon-arrow-left"
|
||||
@click="rightPrevMonth"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
class="el-picker-panel__icon-btn el-icon-d-arrow-right"
|
||||
@click="rightNextYear"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
class="el-picker-panel__icon-btn el-icon-arrow-right"
|
||||
@click="rightNextMonth"
|
||||
></button>
|
||||
<div>{{ rightLabel }}</div>
|
||||
</div>
|
||||
<date-table
|
||||
selection-mode="range"
|
||||
:date="rightDate"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
:range-state="rangeState"
|
||||
:disabled-date="disabledDate"
|
||||
:cell-class-name="cellClassName"
|
||||
@changerange="handleChangeRange"
|
||||
@pick="handleRangePick"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showTime" class="el-picker-panel__footer">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
class="el-picker-panel__link-btn"
|
||||
@click="handleClear"
|
||||
>
|
||||
{{ t('el.datepicker.clear') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
size="mini"
|
||||
class="el-picker-panel__link-btn"
|
||||
:disabled="btnDisabled"
|
||||
@click="handleConfirm(false)"
|
||||
>
|
||||
{{ t('el.datepicker.confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {
|
||||
defineComponent,
|
||||
computed,
|
||||
ref,
|
||||
PropType,
|
||||
inject,
|
||||
watch,
|
||||
} from 'vue'
|
||||
import { t } from '@element-plus/locale'
|
||||
import {
|
||||
extractDateFormat,
|
||||
extractTimeFormat,
|
||||
} from '@element-plus/time-picker/src/common/date-utils'
|
||||
import { ClickOutside } from '@element-plus/directives'
|
||||
import TimePickPanel from '@element-plus/time-picker/src/time-picker-com/panel-time-pick.vue'
|
||||
import dayjs, { Dayjs } from 'dayjs'
|
||||
import DateTable from './basic-date-table.vue'
|
||||
import ElInput from '@element-plus/input/src/index.vue'
|
||||
import { Button as ElButton } from '@element-plus/button'
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
directives: { clickoutside: ClickOutside },
|
||||
|
||||
components: { TimePickPanel, DateTable, ElInput, ElButton },
|
||||
|
||||
props:{
|
||||
unlinkPanels: Boolean,
|
||||
parsedValue: {
|
||||
type: Array as PropType<Dayjs[]>,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['pick', 'set-picker-option'],
|
||||
|
||||
setup(props, ctx) {
|
||||
const leftDate = ref(dayjs())
|
||||
const rightDate = ref(dayjs().add(1, 'month'))
|
||||
const minDate = ref(null)
|
||||
const maxDate = ref(null)
|
||||
const dateUserInput = ref({
|
||||
min: null,
|
||||
max: null,
|
||||
})
|
||||
|
||||
const timeUserInput = ref({
|
||||
min: null,
|
||||
max: null,
|
||||
})
|
||||
|
||||
const leftLabel = computed(() => {
|
||||
return leftDate.value.year() + ' ' + t('el.datepicker.year') + ' ' + t(`el.datepicker.month${ leftDate.value.month() + 1 }`)
|
||||
})
|
||||
|
||||
const rightLabel = computed(() => {
|
||||
return rightDate.value.year() + ' ' + t('el.datepicker.year') + ' ' + t(`el.datepicker.month${ rightDate.value.month() + 1 }`)
|
||||
})
|
||||
|
||||
const leftYear = computed(() => {
|
||||
return leftDate.value.year()
|
||||
})
|
||||
|
||||
const leftMonth = computed(() => {
|
||||
return leftDate.value.month()
|
||||
})
|
||||
|
||||
const rightYear = computed(() => {
|
||||
return rightDate.value.year()
|
||||
})
|
||||
|
||||
const rightMonth = computed(() => {
|
||||
return rightDate.value.month()
|
||||
})
|
||||
|
||||
const hasShortcuts = computed(() => !!shortcuts.length)
|
||||
|
||||
const minVisibleDate = computed(() => {
|
||||
if (dateUserInput.value.min !== null) return dateUserInput.value.min
|
||||
if (minDate.value) return minDate.value.format(dateFormat.value)
|
||||
return ''
|
||||
})
|
||||
|
||||
const maxVisibleDate = computed(() => {
|
||||
if (dateUserInput.value.max !== null) return dateUserInput.value.max
|
||||
if (maxDate.value || minDate.value) return ((maxDate.value || minDate.value)).format(dateFormat.value)
|
||||
return ''
|
||||
})
|
||||
|
||||
const minVisibleTime = computed(() => {
|
||||
if (timeUserInput.value.min !== null) return timeUserInput.value.min
|
||||
if (minDate.value) return minDate.value.format(timeFormat.value)
|
||||
return ''
|
||||
})
|
||||
|
||||
const maxVisibleTime = computed(() => {
|
||||
if (timeUserInput.value.max !== null) return timeUserInput.value.max
|
||||
if (maxDate.value || minDate.value) return ((maxDate.value || minDate.value)).format(timeFormat.value)
|
||||
return ''
|
||||
})
|
||||
|
||||
const timeFormat = computed(() => {
|
||||
return extractTimeFormat(format)
|
||||
})
|
||||
|
||||
const dateFormat = computed(() => {
|
||||
return extractDateFormat(format)
|
||||
})
|
||||
|
||||
const leftPrevYear = () => {
|
||||
leftDate.value = leftDate.value.subtract(1, 'year')
|
||||
if (!props.unlinkPanels) {
|
||||
rightDate.value = leftDate.value.add(1, 'month')
|
||||
}
|
||||
}
|
||||
|
||||
const leftPrevMonth = () => {
|
||||
leftDate.value = leftDate.value.subtract(1, 'month')
|
||||
if (!props.unlinkPanels) {
|
||||
rightDate.value = leftDate.value.add(1, 'month')
|
||||
}
|
||||
}
|
||||
|
||||
const rightNextYear = () => {
|
||||
if (!props.unlinkPanels) {
|
||||
leftDate.value = leftDate.value.add(1, 'year')
|
||||
rightDate.value = leftDate.value.add(1, 'month')
|
||||
} else {
|
||||
rightDate.value = rightDate.value.add(1, 'year')
|
||||
}
|
||||
}
|
||||
|
||||
const rightNextMonth = () => {
|
||||
if (!props.unlinkPanels) {
|
||||
leftDate.value = leftDate.value.add(1, 'month')
|
||||
rightDate.value = leftDate.value.add(1, 'month')
|
||||
} else {
|
||||
rightDate.value = rightDate.value.add(1, 'month')
|
||||
}
|
||||
}
|
||||
|
||||
const leftNextYear = () => {
|
||||
leftDate.value = leftDate.value.add(1, 'year')
|
||||
}
|
||||
|
||||
const leftNextMonth = () => {
|
||||
leftDate.value = leftDate.value.add(1, 'month')
|
||||
}
|
||||
|
||||
const rightPrevYear = () => {
|
||||
rightDate.value = rightDate.value.subtract(1, 'year')
|
||||
}
|
||||
|
||||
const rightPrevMonth = () => {
|
||||
rightDate.value = rightDate.value.subtract(1, 'month')
|
||||
}
|
||||
|
||||
const enableMonthArrow = computed(() => {
|
||||
const nextMonth = (leftMonth.value + 1) % 12
|
||||
const yearOffset = leftMonth.value + 1 >= 12 ? 1 : 0
|
||||
return props.unlinkPanels && new Date(leftYear.value + yearOffset, nextMonth) < new Date(rightYear.value, rightMonth.value)
|
||||
})
|
||||
|
||||
const enableYearArrow = computed(() => {
|
||||
return props.unlinkPanels && rightYear.value * 12 + rightMonth.value - (leftYear.value * 12 + leftMonth.value + 1) >= 12
|
||||
})
|
||||
|
||||
const isValidValue = value => {
|
||||
return Array.isArray(value) &&
|
||||
value && value[0] && value[1] &&
|
||||
value[0].valueOf() <= value[1].valueOf()
|
||||
}
|
||||
|
||||
const rangeState = ref({
|
||||
endDate: null,
|
||||
selecting: false,
|
||||
})
|
||||
|
||||
const btnDisabled = computed(() => {
|
||||
return !(minDate.value && maxDate.value && !rangeState.value.selecting && isValidValue([minDate.value, maxDate.value]))
|
||||
})
|
||||
|
||||
const handleChangeRange = val => {
|
||||
rangeState.value = val
|
||||
}
|
||||
|
||||
const onSelect = selecting => {
|
||||
rangeState.value.selecting = selecting
|
||||
if (!selecting) {
|
||||
rangeState.value.endDate = null
|
||||
}
|
||||
}
|
||||
|
||||
const showTime = computed(() => props.type === 'datetime' || props.type === 'datetimerange')
|
||||
|
||||
const handleConfirm = (visible = false) => {
|
||||
if (isValidValue([minDate.value, maxDate.value])) {
|
||||
ctx.emit('pick', [minDate.value, maxDate.value], visible)
|
||||
}
|
||||
}
|
||||
|
||||
const formatEmit = (emitDayjs: Dayjs, index?) => {
|
||||
if (!emitDayjs) return
|
||||
if (defaultTime) {
|
||||
const defaultTimeD = dayjs(defaultTime[index] || defaultTime)
|
||||
return defaultTimeD.year(emitDayjs.year()).month(emitDayjs.month()).date(emitDayjs.date())
|
||||
}
|
||||
return emitDayjs
|
||||
}
|
||||
|
||||
const handleRangePick = (val, close = true) => {
|
||||
const minDate_ = formatEmit(val.minDate, 0)
|
||||
const maxDate_ = formatEmit(val.maxDate, 1)
|
||||
|
||||
if (maxDate.value === maxDate_ && minDate.value === minDate_) {
|
||||
return
|
||||
}
|
||||
maxDate.value = maxDate_
|
||||
minDate.value = minDate_
|
||||
|
||||
if (!close || showTime.value) return
|
||||
handleConfirm()
|
||||
}
|
||||
|
||||
const handleShortcutClick = shortcut => {
|
||||
if (shortcut.value) {
|
||||
ctx.emit('pick', [dayjs(shortcut.value[0]), dayjs(shortcut.value[1])])
|
||||
return
|
||||
}
|
||||
if (shortcut.onClick) {
|
||||
shortcut.onClick(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
const minTimePickerVisible = ref(false)
|
||||
const maxTimePickerVisible = ref(false)
|
||||
|
||||
const handleMinTimeClose = () => {
|
||||
minTimePickerVisible.value = false
|
||||
}
|
||||
|
||||
const handleMaxTimeClose = () => {
|
||||
maxTimePickerVisible.value = false
|
||||
}
|
||||
|
||||
const handleDateInput = (value, type) => {
|
||||
dateUserInput.value[type] = value
|
||||
const parsedValueD = dayjs(value, dateFormat.value)
|
||||
|
||||
if (parsedValueD.isValid()) {
|
||||
if (disabledDate &&
|
||||
disabledDate(parsedValueD.toDate())) {
|
||||
return
|
||||
}
|
||||
if (type === 'min') {
|
||||
leftDate.value = parsedValueD
|
||||
minDate.value = (minDate.value || leftDate.value).year(parsedValueD.year()).month(parsedValueD.month()).date(parsedValueD.date())
|
||||
if (!props.unlinkPanels) {
|
||||
rightDate.value = parsedValueD.add(1, 'month')
|
||||
maxDate.value = minDate.value.add(1, 'month')
|
||||
}
|
||||
} else {
|
||||
rightDate.value = parsedValueD
|
||||
maxDate.value = (maxDate.value || rightDate.value).year(parsedValueD.year()).month(parsedValueD.month()).date(parsedValueD.date())
|
||||
if (!props.unlinkPanels) {
|
||||
leftDate.value = parsedValueD.subtract(1, 'month')
|
||||
minDate.value = maxDate.value.subtract(1, 'month')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleDateChange = (value, type) => {
|
||||
dateUserInput.value[type] = null
|
||||
}
|
||||
|
||||
const handleTimeInput = (value, type) => {
|
||||
timeUserInput.value[type] = value
|
||||
const parsedValueD = dayjs(value, timeFormat.value)
|
||||
|
||||
if (parsedValueD.isValid()) {
|
||||
if (type === 'min') {
|
||||
minTimePickerVisible.value = true
|
||||
minDate.value = (minDate.value || leftDate.value).hour(parsedValueD.hour()).minute(parsedValueD.minute()).second(parsedValueD.second())
|
||||
if (!maxDate.value || maxDate.value.isBefore(minDate.value)) {
|
||||
maxDate.value = minDate.value
|
||||
}
|
||||
} else {
|
||||
maxTimePickerVisible.value = true
|
||||
maxDate.value = (maxDate.value || rightDate.value).hour(parsedValueD.hour()).minute(parsedValueD.minute()).second(parsedValueD.second())
|
||||
rightDate.value = maxDate.value
|
||||
if (maxDate.value && maxDate.value.isBefore(minDate.value)) {
|
||||
minDate.value = maxDate.value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleTimeChange = (value, type) => {
|
||||
timeUserInput.value[type] = null
|
||||
if (type === 'min') {
|
||||
leftDate.value = minDate.value
|
||||
minTimePickerVisible.value = false
|
||||
} else {
|
||||
rightDate.value = maxDate.value
|
||||
maxTimePickerVisible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const handleMinTimePick = (value, visible, first) => {
|
||||
if (timeUserInput.value.min) return
|
||||
if (value) {
|
||||
leftDate.value = value
|
||||
minDate.value = (minDate.value || leftDate.value).hour(value.hour()).minute(value.minute()).second(value.second())
|
||||
}
|
||||
|
||||
if (!first) {
|
||||
minTimePickerVisible.value = visible
|
||||
}
|
||||
|
||||
if (!maxDate.value || maxDate.value.isBefore(minDate.value)) {
|
||||
maxDate.value = minDate.value
|
||||
}
|
||||
}
|
||||
|
||||
const handleMaxTimePick = (value, visible, first) => {
|
||||
if (timeUserInput.value.max) return
|
||||
if (value) {
|
||||
rightDate.value = value
|
||||
maxDate.value = (maxDate.value || rightDate.value).hour(value.hour()).minute(value.minute()).second(value.second())
|
||||
}
|
||||
|
||||
if (!first) {
|
||||
maxTimePickerVisible.value = visible
|
||||
}
|
||||
|
||||
if (maxDate.value && maxDate.value.isBefore(minDate.value)) {
|
||||
minDate.value = maxDate.value
|
||||
}
|
||||
}
|
||||
|
||||
const handleClear = () => {
|
||||
minDate.value = null
|
||||
maxDate.value = null
|
||||
leftDate.value = getDefaultValue()[0]
|
||||
rightDate.value = leftDate.value.add(1, 'month')
|
||||
ctx.emit('pick', null)
|
||||
}
|
||||
|
||||
const formatToString = value => {
|
||||
return value.map(_=> _.format(format))
|
||||
}
|
||||
|
||||
const getDefaultValue = () => {
|
||||
let start
|
||||
if (Array.isArray(defaultValue)) {
|
||||
const left = dayjs(defaultValue[0])
|
||||
let right = dayjs(defaultValue[1])
|
||||
if (!props.unlinkPanels) {
|
||||
right = left.add(1, 'month')
|
||||
}
|
||||
return [left, right]
|
||||
} else if (defaultValue) {
|
||||
start = dayjs(defaultValue)
|
||||
} else {
|
||||
start = dayjs()
|
||||
}
|
||||
return [start, start.add(1, 'month')]
|
||||
}
|
||||
|
||||
// pickerBase.hub.emit('SetPickerOption', ['isValidValue', isValidValue])
|
||||
ctx.emit('set-picker-option', ['formatToString', formatToString])
|
||||
|
||||
const pickerBase = inject('EP_PICKER_BASE') as any
|
||||
const { shortcuts, disabledDate, cellClassName, format, defaultTime, defaultValue, arrowControl } = pickerBase.props
|
||||
|
||||
watch(() => props.parsedValue, newVal => {
|
||||
if (newVal && newVal.length === 2) {
|
||||
minDate.value = newVal[0]
|
||||
maxDate.value = newVal[1]
|
||||
leftDate.value = minDate.value
|
||||
if (props.unlinkPanels && maxDate.value) {
|
||||
const minDateYear = minDate.value.year()
|
||||
const minDateMonth = minDate.value.month()
|
||||
const maxDateYear = maxDate.value.year()
|
||||
const maxDateMonth = maxDate.value.month()
|
||||
rightDate.value = minDateYear === maxDateYear && minDateMonth === maxDateMonth
|
||||
? maxDate.value.add(1, 'month')
|
||||
: maxDate.value
|
||||
} else {
|
||||
rightDate.value = leftDate.value.add(1, 'month')
|
||||
}
|
||||
} else {
|
||||
const defaultArr = getDefaultValue()
|
||||
leftDate.value = defaultArr[0]
|
||||
rightDate.value = defaultArr[1]
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
return {
|
||||
shortcuts,
|
||||
disabledDate,
|
||||
cellClassName,
|
||||
minTimePickerVisible,
|
||||
maxTimePickerVisible,
|
||||
handleMinTimeClose,
|
||||
handleMaxTimeClose,
|
||||
handleShortcutClick,
|
||||
rangeState,
|
||||
minDate,
|
||||
maxDate,
|
||||
handleRangePick,
|
||||
onSelect,
|
||||
handleChangeRange,
|
||||
btnDisabled,
|
||||
enableYearArrow,
|
||||
enableMonthArrow,
|
||||
rightPrevMonth,
|
||||
rightPrevYear,
|
||||
rightNextMonth,
|
||||
rightNextYear,
|
||||
leftPrevMonth,
|
||||
leftPrevYear,
|
||||
leftNextMonth,
|
||||
leftNextYear,
|
||||
hasShortcuts,
|
||||
leftLabel,
|
||||
rightLabel,
|
||||
leftDate,
|
||||
rightDate,
|
||||
showTime,
|
||||
t,
|
||||
minVisibleDate,
|
||||
maxVisibleDate,
|
||||
minVisibleTime,
|
||||
maxVisibleTime,
|
||||
arrowControl,
|
||||
handleDateInput,
|
||||
handleDateChange,
|
||||
handleTimeInput,
|
||||
handleTimeChange,
|
||||
handleMinTimePick,
|
||||
handleMaxTimePick,
|
||||
handleClear,
|
||||
handleConfirm,
|
||||
timeFormat,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
.el-time-panel {
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
289
packages/date-picker/src/date-picker-com/panel-month-range.vue
Normal file
289
packages/date-picker/src/date-picker-com/panel-month-range.vue
Normal file
@ -0,0 +1,289 @@
|
||||
<template>
|
||||
<transition name="el-zoom-in-top">
|
||||
<div
|
||||
class="el-picker-panel el-date-range-picker"
|
||||
:class="[{
|
||||
'has-sidebar': $slots.sidebar || hasShortcuts
|
||||
}]"
|
||||
>
|
||||
<div class="el-picker-panel__body-wrapper">
|
||||
<slot name="sidebar" class="el-picker-panel__sidebar"></slot>
|
||||
<div v-if="hasShortcuts" class="el-picker-panel__sidebar">
|
||||
<button
|
||||
v-for="(shortcut, key) in shortcuts"
|
||||
:key="key"
|
||||
type="button"
|
||||
class="el-picker-panel__shortcut"
|
||||
@click="handleShortcutClick(shortcut)"
|
||||
>
|
||||
{{ shortcut.text }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="el-picker-panel__body">
|
||||
<div class="el-picker-panel__content el-date-range-picker__content is-left">
|
||||
<div class="el-date-range-picker__header">
|
||||
<button
|
||||
type="button"
|
||||
class="el-picker-panel__icon-btn el-icon-d-arrow-left"
|
||||
@click="leftPrevYear"
|
||||
></button>
|
||||
<button
|
||||
v-if="unlinkPanels"
|
||||
type="button"
|
||||
:disabled="!enableYearArrow"
|
||||
:class="{ 'is-disabled': !enableYearArrow }"
|
||||
class="el-picker-panel__icon-btn el-icon-d-arrow-right"
|
||||
@click="leftNextYear"
|
||||
></button>
|
||||
<div>{{ leftLabel }}</div>
|
||||
</div>
|
||||
<month-table
|
||||
selection-mode="range"
|
||||
:date="leftDate"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
:range-state="rangeState"
|
||||
:disabled-date="disabledDate"
|
||||
@changerange="handleChangeRange"
|
||||
@pick="handleRangePick"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</div>
|
||||
<div class="el-picker-panel__content el-date-range-picker__content is-right">
|
||||
<div class="el-date-range-picker__header">
|
||||
<button
|
||||
v-if="unlinkPanels"
|
||||
type="button"
|
||||
:disabled="!enableYearArrow"
|
||||
:class="{ 'is-disabled': !enableYearArrow }"
|
||||
class="el-picker-panel__icon-btn el-icon-d-arrow-left"
|
||||
@click="rightPrevYear"
|
||||
></button>
|
||||
<button
|
||||
type="button"
|
||||
class="el-picker-panel__icon-btn el-icon-d-arrow-right"
|
||||
@click="rightNextYear"
|
||||
></button>
|
||||
<div>{{ rightLabel }}</div>
|
||||
</div>
|
||||
<month-table
|
||||
selection-mode="range"
|
||||
:date="rightDate"
|
||||
:min-date="minDate"
|
||||
:max-date="maxDate"
|
||||
:range-state="rangeState"
|
||||
:disabled-date="disabledDate"
|
||||
@changerange="handleChangeRange"
|
||||
@pick="handleRangePick"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { t } from '@element-plus/locale'
|
||||
import MonthTable from './basic-month-table.vue'
|
||||
import dayjs, { Dayjs } from 'dayjs'
|
||||
import {
|
||||
defineComponent,
|
||||
computed,
|
||||
ref,
|
||||
PropType,
|
||||
watch,
|
||||
inject,
|
||||
} from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
components: { MonthTable },
|
||||
|
||||
props:{
|
||||
unlinkPanels: Boolean,
|
||||
parsedValue: {
|
||||
type: Array as PropType<Dayjs[]>,
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['pick', 'set-picker-option'],
|
||||
|
||||
setup(props, ctx) {
|
||||
const leftDate = ref(dayjs())
|
||||
const rightDate = ref(dayjs().add(1, 'year'))
|
||||
|
||||
const hasShortcuts = computed(() => !!shortcuts.length)
|
||||
|
||||
const handleShortcutClick = shortcut => {
|
||||
if (shortcut.value) {
|
||||
ctx.emit('pick', [dayjs(shortcut.value[0]), dayjs(shortcut.value[1])])
|
||||
return
|
||||
}
|
||||
if (shortcut.onClick) {
|
||||
shortcut.onClick(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
const leftPrevYear = () => {
|
||||
leftDate.value = leftDate.value.subtract(1, 'year')
|
||||
if (!props.unlinkPanels) {
|
||||
rightDate.value = rightDate.value.subtract(1, 'year')
|
||||
}
|
||||
}
|
||||
|
||||
const rightNextYear = () => {
|
||||
if (!props.unlinkPanels) {
|
||||
leftDate.value = leftDate.value.add(1, 'year')
|
||||
}
|
||||
rightDate.value = rightDate.value.add(1, 'year')
|
||||
}
|
||||
|
||||
const leftNextYear = () => {
|
||||
leftDate.value = leftDate.value.add(1, 'year')
|
||||
}
|
||||
|
||||
const rightPrevYear = () =>{
|
||||
rightDate.value = rightDate.value.subtract(1, 'year')
|
||||
}
|
||||
const leftLabel = computed(() => {
|
||||
return `${leftDate.value.year()} ${t('el.datepicker.year')}`
|
||||
})
|
||||
|
||||
const rightLabel = computed(() => {
|
||||
return `${rightDate.value.year()} ${t('el.datepicker.year')}`
|
||||
})
|
||||
|
||||
const leftYear = computed(() =>{
|
||||
return leftDate.value.year()
|
||||
})
|
||||
|
||||
const rightYear = computed(() => {
|
||||
return rightDate.value.year() === leftDate.value.year() ? leftDate.value.year() + 1 : rightDate.value.year()
|
||||
})
|
||||
|
||||
const enableYearArrow = computed(() => {
|
||||
return props.unlinkPanels && rightYear.value > leftYear.value + 1
|
||||
})
|
||||
|
||||
const minDate = ref(null)
|
||||
const maxDate = ref(null)
|
||||
|
||||
const rangeState = ref({
|
||||
endDate: null,
|
||||
selecting: false,
|
||||
})
|
||||
|
||||
const handleChangeRange = val => {
|
||||
rangeState.value = val
|
||||
}
|
||||
|
||||
const handleRangePick = (val, close = true) => {
|
||||
// const defaultTime = props.defaultTime || []
|
||||
// const minDate_ = modifyWithTimeString(val.minDate, defaultTime[0])
|
||||
// const maxDate_ = modifyWithTimeString(val.maxDate, defaultTime[1])
|
||||
// todo
|
||||
const minDate_ = val.minDate
|
||||
const maxDate_ = val.maxDate
|
||||
if (maxDate.value === maxDate_ && minDate.value === minDate_) {
|
||||
return
|
||||
}
|
||||
maxDate.value = maxDate_
|
||||
minDate.value = minDate_
|
||||
|
||||
if (!close) return
|
||||
handleConfirm()
|
||||
}
|
||||
|
||||
const isValidValue = value => {
|
||||
return Array.isArray(value) &&
|
||||
value && value[0] && value[1] &&
|
||||
value[0].valueOf() <= value[1].valueOf()
|
||||
}
|
||||
|
||||
const handleConfirm = (visible = false) => {
|
||||
if (isValidValue([minDate.value, maxDate.value])) {
|
||||
ctx.emit('pick', [minDate.value, maxDate.value], visible)
|
||||
}
|
||||
}
|
||||
|
||||
const onSelect = selecting => {
|
||||
rangeState.value.selecting = selecting
|
||||
if (!selecting) {
|
||||
rangeState.value.endDate = null
|
||||
}
|
||||
}
|
||||
|
||||
const formatToString = value => {
|
||||
return value.map(_=> _.format(format))
|
||||
}
|
||||
|
||||
const getDefaultValue = () => {
|
||||
let start
|
||||
if (Array.isArray(defaultValue)) {
|
||||
const left = dayjs(defaultValue[0])
|
||||
let right = dayjs(defaultValue[1])
|
||||
if (!props.unlinkPanels) {
|
||||
right = left.add(1, 'year')
|
||||
}
|
||||
return [left, right]
|
||||
} else if (defaultValue) {
|
||||
start = dayjs(defaultValue)
|
||||
} else {
|
||||
start = dayjs()
|
||||
}
|
||||
return [start, start.add(1, 'year')]
|
||||
}
|
||||
|
||||
// pickerBase.hub.emit('SetPickerOption', ['isValidValue', isValidValue])
|
||||
ctx.emit('set-picker-option', ['formatToString', formatToString])
|
||||
const pickerBase = inject('EP_PICKER_BASE') as any
|
||||
const { shortcuts, disabledDate, format, defaultValue } = pickerBase.props
|
||||
|
||||
watch(() => props.parsedValue, newVal => {
|
||||
if (newVal && newVal.length === 2) {
|
||||
minDate.value = newVal[0]
|
||||
maxDate.value = newVal[1]
|
||||
leftDate.value = minDate.value
|
||||
if (props.unlinkPanels && maxDate.value) {
|
||||
const minDateYear = minDate.value.year()
|
||||
const maxDateYear = maxDate.value.year()
|
||||
rightDate.value = minDateYear === maxDateYear
|
||||
? maxDate.value.add(1, 'year')
|
||||
: maxDate.value
|
||||
} else {
|
||||
rightDate.value = leftDate.value.add(1, 'year')
|
||||
}
|
||||
} else {
|
||||
const defaultArr = getDefaultValue()
|
||||
leftDate.value = defaultArr[0]
|
||||
rightDate.value = defaultArr[1]
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
return {
|
||||
shortcuts,
|
||||
disabledDate,
|
||||
onSelect,
|
||||
handleRangePick,
|
||||
rangeState,
|
||||
handleChangeRange,
|
||||
minDate,
|
||||
maxDate,
|
||||
enableYearArrow,
|
||||
leftLabel,
|
||||
rightLabel,
|
||||
leftNextYear,
|
||||
leftPrevYear,
|
||||
rightNextYear,
|
||||
rightPrevYear,
|
||||
t,
|
||||
leftDate,
|
||||
rightDate,
|
||||
hasShortcuts,
|
||||
handleShortcutClick,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
53
packages/date-picker/src/date-picker.ts
Normal file
53
packages/date-picker/src/date-picker.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { DEFAULT_FORMATS_DATE, DEFAULT_FORMATS_DATEPICKER } from '@element-plus/time-picker/src/common/constant'
|
||||
import Picker from '@element-plus/time-picker/src/common/picker.vue'
|
||||
import DatePickPanel from './date-picker-com/panel-date-pick.vue'
|
||||
import DateRangePickPanel from './date-picker-com/panel-date-range.vue'
|
||||
import MonthRangePickPanel from './date-picker-com/panel-month-range.vue'
|
||||
import dayjs from 'dayjs'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||
import advancedFormat from 'dayjs/plugin/advancedFormat'
|
||||
import localeData from 'dayjs/plugin/localeData'
|
||||
import weekOfYear from 'dayjs/plugin/weekOfYear'
|
||||
import weekYear from 'dayjs/plugin/weekYear'
|
||||
import isLeapYear from 'dayjs/plugin/isLeapYear'
|
||||
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
|
||||
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
|
||||
import { h } from 'vue'
|
||||
dayjs.extend(isLeapYear)
|
||||
dayjs.extend(localeData)
|
||||
dayjs.extend(advancedFormat)
|
||||
dayjs.extend(customParseFormat)
|
||||
dayjs.extend(weekOfYear)
|
||||
dayjs.extend(weekYear)
|
||||
dayjs.extend(isSameOrAfter)
|
||||
dayjs.extend(isSameOrBefore)
|
||||
|
||||
const getPanel = function(type) {
|
||||
if (type === 'daterange' || type === 'datetimerange') {
|
||||
return DateRangePickPanel
|
||||
} else if (type === 'monthrange') {
|
||||
return MonthRangePickPanel
|
||||
}
|
||||
return DatePickPanel
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'ElDatePicker',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'date',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const format = DEFAULT_FORMATS_DATEPICKER[props.type] || DEFAULT_FORMATS_DATE
|
||||
return () => h(Picker, {
|
||||
format,
|
||||
type: props.type,
|
||||
...props,
|
||||
},
|
||||
{
|
||||
default: scopedProps => h(getPanel(props.type), scopedProps),
|
||||
})
|
||||
},
|
||||
}
|
@ -28,6 +28,7 @@ import ElSteps from '@element-plus/steps'
|
||||
import ElCollapse from '@element-plus/collapse'
|
||||
import ElPopper from '@element-plus/popper'
|
||||
import ElTimePicker from '@element-plus/time-picker'
|
||||
import ElDatePicker from '@element-plus/date-picker'
|
||||
import ElTabs from '@element-plus/tabs'
|
||||
import ElTooltip from '@element-plus/tooltip'
|
||||
import ElSlider from '@element-plus/slider'
|
||||
@ -71,6 +72,7 @@ export {
|
||||
ElRadio,
|
||||
ElCollapse,
|
||||
ElTimePicker,
|
||||
ElDatePicker,
|
||||
ElTabs,
|
||||
ElTooltip,
|
||||
ElSlider,
|
||||
@ -116,6 +118,7 @@ const install = (app: App): void => {
|
||||
ElCollapse(app)
|
||||
ElPopper(app)
|
||||
ElTimePicker(app)
|
||||
ElDatePicker(app)
|
||||
ElTabs(app)
|
||||
ElTooltip(app)
|
||||
ElSlider(app)
|
||||
|
@ -161,8 +161,8 @@ export default defineComponent({
|
||||
default: 'text',
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<'large' | 'medium' | 'small' | 'mini'>,
|
||||
validator: (val: string) => ['large', 'medium', 'small', 'mini'].includes(val),
|
||||
type: String as PropType<'large' | 'medium' | 'small' | 'mini' | null>,
|
||||
validator: (val: string) => !val || ['large', 'medium', 'small', 'mini'].includes(val),
|
||||
},
|
||||
resize: {
|
||||
type: String as PropType<'none' | 'both' | 'horizontal' | 'vertical'>,
|
||||
|
@ -3,3 +3,4 @@ export { default as defineGetter } from './define-getter'
|
||||
export { default as makeScroll } from './make-scroll'
|
||||
export { default as sleep } from './sleep'
|
||||
export { default as tick } from './tick'
|
||||
export { default as triggerEvent } from './trigger-event'
|
||||
|
27
packages/test-utils/trigger-event.ts
Normal file
27
packages/test-utils/trigger-event.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Trigger event
|
||||
* mouseenter, mouseleave, mouseover, keyup, change, click
|
||||
* @param {Element} elm
|
||||
* @param {String} name
|
||||
* @param {*} opts
|
||||
*/
|
||||
const triggerEvent = (elm, name, ...opts) => {
|
||||
let eventName
|
||||
|
||||
if (/^mouse|click/.test(name)) {
|
||||
eventName = 'MouseEvents'
|
||||
} else if (/^key/.test(name)) {
|
||||
eventName = 'KeyboardEvent'
|
||||
} else {
|
||||
eventName = 'HTMLEvents'
|
||||
}
|
||||
const evt = document.createEvent(eventName)
|
||||
|
||||
evt.initEvent(name, ...opts)
|
||||
elm.dispatchEvent
|
||||
? elm.dispatchEvent(evt)
|
||||
: elm.fireEvent('on' + name, evt)
|
||||
|
||||
return elm
|
||||
}
|
||||
export default triggerEvent
|
@ -1,6 +1,7 @@
|
||||
@import "../common/var";
|
||||
|
||||
@include b(picker-panel) {
|
||||
position: relative;
|
||||
color: $--color-text-regular;
|
||||
border: 1px solid $--datepicker-border-color;
|
||||
box-shadow: $--box-shadow-light;
|
||||
|
@ -1,12 +1,12 @@
|
||||
// daterange: 'YYYY-MM-DD',
|
||||
// monthrange: 'YYYY-MM',
|
||||
// datetimerange: 'yyyy-MM-DD HH:mm:ss',
|
||||
export const DEFAULT_FORMATS_TIME = 'HH:mm:ss'
|
||||
export const DEFAULT_FORMATS_DATE = 'YYYY-MM-DD'
|
||||
export const DEFAULT_FORMATS_DATEPICKER = {
|
||||
'date': DEFAULT_FORMATS_DATE,
|
||||
'week': 'YYYYwWW',
|
||||
'year': 'YYYY',
|
||||
'month': 'YYYY-MM',
|
||||
'datetime': 'YYYY-MM-DD HH:mm:ss',
|
||||
date: DEFAULT_FORMATS_DATE,
|
||||
week: 'gggg[w]ww',
|
||||
year: 'YYYY',
|
||||
month: 'YYYY-MM',
|
||||
datetime: `${DEFAULT_FORMATS_DATE} ${DEFAULT_FORMATS_TIME}`,
|
||||
monthrange: 'YYYY-MM',
|
||||
daterange: DEFAULT_FORMATS_DATE,
|
||||
datetimerange: `${DEFAULT_FORMATS_DATE} ${DEFAULT_FORMATS_TIME}`,
|
||||
}
|
||||
|
16
packages/time-picker/src/common/date-utils.ts
Normal file
16
packages/time-picker/src/common/date-utils.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export const rangeArr = n => {
|
||||
return Array.from(Array(n).keys())
|
||||
}
|
||||
|
||||
export const extractDateFormat = format => {
|
||||
return format
|
||||
.replace(/\W?m{1,2}|\W?ZZ/g, '')
|
||||
.replace(/\W?h{1,2}|\W?s{1,3}|\W?a/gi, '')
|
||||
.trim()
|
||||
}
|
||||
|
||||
export const extractTimeFormat = format => {
|
||||
return format
|
||||
.replace(/\W?D{1,2}|\W?Do|\W?d{1,4}|\W?M{1,4}|\W?Y{2,4}/g, '')
|
||||
.trim()
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
<!-- todo popper custom popper-class -->
|
||||
<!-- todo bug handleKeydown event twice -->
|
||||
<el-popper
|
||||
ref="popper"
|
||||
v-model:visible="pickerVisible"
|
||||
pure
|
||||
manual-mode
|
||||
@ -21,7 +22,7 @@
|
||||
:placeholder="placeholder"
|
||||
class="el-date-editor"
|
||||
:class="'el-date-editor--' + type"
|
||||
:readonly="!editable || readonly || type === 'dates' || type === 'week'"
|
||||
:readonly="!editable || readonly || isDatesPicker || type === 'week'"
|
||||
@input="onUserInput"
|
||||
@focus="handleFocus"
|
||||
@keydown="handleKeydown"
|
||||
@ -108,6 +109,7 @@
|
||||
v-bind="$attrs"
|
||||
@pick="onPick"
|
||||
@select-range="setSelectionRange"
|
||||
@set-picker-option="onSetPickerOption"
|
||||
@mousedown.stop
|
||||
></slot>
|
||||
</template>
|
||||
@ -128,7 +130,6 @@ import { ClickOutside } from '@element-plus/directives'
|
||||
import ElInput from '@element-plus/input/src/index.vue'
|
||||
import { Popper as ElPopper } from '@element-plus/popper'
|
||||
import { EVENT_CODE } from '@element-plus/utils/aria'
|
||||
import mitt from 'mitt'
|
||||
// Date object and string
|
||||
const dateEquals = function(a, b) {
|
||||
const aIsDate = a instanceof Date
|
||||
@ -166,6 +167,7 @@ interface PickerOptions {
|
||||
parseUserInput: any
|
||||
formatToString: any
|
||||
getRangeAvaliableTime: any
|
||||
getDefaultValue: any
|
||||
panelReady: boolean
|
||||
}
|
||||
export default defineComponent({
|
||||
@ -232,7 +234,9 @@ export default defineComponent({
|
||||
endPlaceholder: String,
|
||||
defaultValue: {
|
||||
type: [Date, Array] as PropType<Date | Date[]>,
|
||||
default: new Date(),
|
||||
},
|
||||
defaultTime: {
|
||||
type: [Date, Array] as PropType<Date | Date[]>,
|
||||
},
|
||||
isRange: {
|
||||
type: Boolean,
|
||||
@ -240,20 +244,30 @@ export default defineComponent({
|
||||
},
|
||||
disabledHours: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
disabledMinutes: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
disabledSeconds: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
disabledDate: {
|
||||
type: Function,
|
||||
},
|
||||
cellClassName: {
|
||||
type: Function,
|
||||
},
|
||||
shortcuts: {
|
||||
type: Array,
|
||||
default: () => ([]),
|
||||
},
|
||||
arrowControl: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'change', 'focus', 'blur'],
|
||||
setup(props, ctx) {
|
||||
const oldValue = ref(props.modelValue)
|
||||
const refContainer = ref(null)
|
||||
const pickerVisible = ref(false)
|
||||
const valueOnOpen = ref(null)
|
||||
@ -295,17 +309,14 @@ export default defineComponent({
|
||||
_inputs[1].focus()
|
||||
}
|
||||
}
|
||||
const onPick = (date: any = '', visible = false, useOldValue = false) => {
|
||||
const onPick = (date: any = '', visible = false) => {
|
||||
pickerVisible.value = visible
|
||||
let result
|
||||
if (useOldValue) {
|
||||
result = oldValue.value
|
||||
if (Array.isArray(date)) {
|
||||
result = date.map(_ => _.toDate())
|
||||
} else {
|
||||
if (Array.isArray(date)) {
|
||||
result = date.map(_ => _.toDate())
|
||||
} else {
|
||||
result = date.toDate()
|
||||
}
|
||||
// clear btn emit null
|
||||
result = date ? date.toDate() : date
|
||||
}
|
||||
userInput.value = null
|
||||
emitInput(result)
|
||||
@ -323,26 +334,18 @@ export default defineComponent({
|
||||
|
||||
const parsedValue = computed(() => {
|
||||
let result
|
||||
if (isRangeInput.value) {
|
||||
if (!props.modelValue) {
|
||||
if (Array.isArray(props.defaultValue)) {
|
||||
result = (props.defaultValue as Array<Date>).map(_=> dayjs(_))
|
||||
} else {
|
||||
result = [
|
||||
dayjs(props.defaultValue as Date),
|
||||
dayjs(props.defaultValue as Date).add(60,'m'),
|
||||
]
|
||||
}
|
||||
} else {
|
||||
result = (props.modelValue as Array<Date>).map(_=> dayjs(_))
|
||||
if (valueIsEmpty.value) {
|
||||
if (pickerOptions.value.getDefaultValue) {
|
||||
result = pickerOptions.value.getDefaultValue()
|
||||
}
|
||||
} else {
|
||||
if (!props.modelValue) {
|
||||
result = dayjs(props.defaultValue as Date)
|
||||
if (Array.isArray(props.modelValue)) {
|
||||
result = props.modelValue.map(_=>dayjs(_))
|
||||
} else {
|
||||
result = dayjs(props.modelValue as Date)
|
||||
}
|
||||
}
|
||||
|
||||
if (pickerOptions.value.getRangeAvaliableTime) {
|
||||
result = pickerOptions.value.getRangeAvaliableTime(result)
|
||||
}
|
||||
@ -351,7 +354,8 @@ export default defineComponent({
|
||||
|
||||
const displayValue = computed(() => {
|
||||
if (!pickerOptions.value.panelReady) return
|
||||
if (!pickerVisible.value && !props.modelValue) return
|
||||
if (!isTimePicker.value && valueIsEmpty.value) return
|
||||
if (!pickerVisible.value && valueIsEmpty.value) return
|
||||
const formattedValue = formatDayjsToString(parsedValue.value)
|
||||
if (Array.isArray(userInput.value)) {
|
||||
return [
|
||||
@ -362,14 +366,27 @@ export default defineComponent({
|
||||
return userInput.value
|
||||
}
|
||||
if (formattedValue) {
|
||||
return props.type === 'dates'
|
||||
return isDatesPicker.value
|
||||
? (formattedValue as Array<string>).join(', ')
|
||||
: formattedValue
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
const isTimeLikePicker = computed(() => {
|
||||
return props.type.indexOf('time') !== -1
|
||||
})
|
||||
|
||||
const isTimePicker = computed(() => {
|
||||
return props.type.indexOf('time') === 0
|
||||
})
|
||||
|
||||
const isDatesPicker = computed(() => {
|
||||
return props.type === 'dates'
|
||||
})
|
||||
|
||||
const triggerClass = computed(() => {
|
||||
return props.prefixIcon || (props.type.indexOf('time') !== -1 ? 'el-icon-time' : 'el-icon-date')
|
||||
return props.prefixIcon || (isTimeLikePicker.value ? 'el-icon-time' : 'el-icon-date')
|
||||
})
|
||||
const showClose = ref(false)
|
||||
const onClearIconClick = event =>{
|
||||
@ -383,7 +400,7 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
const valueIsEmpty = computed(() => {
|
||||
return !props.modelValue
|
||||
return !props.modelValue || (Array.isArray(props.modelValue) && !props.modelValue.length)
|
||||
})
|
||||
const onMouseEnter = () => {
|
||||
if (props.readonly || pickerDisabled.value) return
|
||||
@ -410,7 +427,7 @@ export default defineComponent({
|
||||
pickerVisible.value = false
|
||||
}
|
||||
|
||||
const userInput =ref(null)
|
||||
const userInput = ref(null)
|
||||
|
||||
const handleChange = () => {
|
||||
if (userInput.value) {
|
||||
@ -434,10 +451,12 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const parseUserInputToDayjs = value => {
|
||||
if (!value) return null
|
||||
return pickerOptions.value.parseUserInput(value)
|
||||
}
|
||||
|
||||
const formatDayjsToString = value => {
|
||||
if (!value) return null
|
||||
return pickerOptions.value.formatToString(value)
|
||||
}
|
||||
|
||||
@ -535,16 +554,16 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const pickerOptions = ref({} as PickerOptions)
|
||||
const pickerHub = mitt()
|
||||
pickerHub.on('SetPickerOption', e => {
|
||||
const onSetPickerOption = e => {
|
||||
pickerOptions.value[e[0]] = e[1]
|
||||
pickerOptions.value.panelReady = true
|
||||
})
|
||||
}
|
||||
|
||||
provide('EP_PICKER_BASE', {
|
||||
hub: pickerHub,
|
||||
props,
|
||||
})
|
||||
return {
|
||||
isDatesPicker,
|
||||
handleEndChange,
|
||||
handleStartChange,
|
||||
handleStartInput,
|
||||
@ -568,6 +587,7 @@ export default defineComponent({
|
||||
setSelectionRange,
|
||||
refContainer,
|
||||
pickerDisabled,
|
||||
onSetPickerOption,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -59,7 +59,6 @@ import {
|
||||
nextTick,
|
||||
computed,
|
||||
onMounted,
|
||||
inject,
|
||||
Ref,
|
||||
PropType,
|
||||
watch,
|
||||
@ -97,9 +96,18 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: '', // 'a': am/pm; 'A': AM/PM
|
||||
},
|
||||
disabledHours: {
|
||||
type: Function,
|
||||
},
|
||||
disabledMinutes: {
|
||||
type: Function,
|
||||
},
|
||||
disabledSeconds: {
|
||||
type: Function,
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['change', 'select-range'],
|
||||
emits: ['change', 'select-range', 'set-option'],
|
||||
|
||||
setup(props, ctx) {
|
||||
// data
|
||||
@ -312,18 +320,17 @@ export default defineComponent({
|
||||
return `list${item.charAt(0).toUpperCase() + item.slice(1)}Ref`
|
||||
}
|
||||
|
||||
const pickerPanel = inject('EP_TIMEPICK_PANEL') as any
|
||||
pickerPanel.hub.emit('SetOption',[`${props.role}_scrollDown`, scrollDown])
|
||||
pickerPanel.hub.emit('SetOption',[`${props.role}_emitSelectRange`, emitSelectRange])
|
||||
ctx.emit('set-option',[`${props.role}_scrollDown`, scrollDown])
|
||||
ctx.emit('set-option',[`${props.role}_emitSelectRange`, emitSelectRange])
|
||||
|
||||
const {
|
||||
getHoursList,
|
||||
getMinutesList,
|
||||
getSecondsList,
|
||||
} = getTimeLists(
|
||||
pickerPanel.methods.disabledHours,
|
||||
pickerPanel.methods.disabledMinutes,
|
||||
pickerPanel.methods.disabledSeconds,
|
||||
props.disabledHours,
|
||||
props.disabledMinutes,
|
||||
props.disabledSeconds,
|
||||
)
|
||||
|
||||
watch(() => props.spinnerDate, () => {
|
||||
|
@ -7,12 +7,16 @@
|
||||
<div class="el-time-panel__content" :class="{ 'has-seconds': showSeconds }">
|
||||
<time-spinner
|
||||
ref="spinner"
|
||||
role="start"
|
||||
:role="datetimeRole || 'start'"
|
||||
:arrow-control="arrowControl"
|
||||
:show-seconds="showSeconds"
|
||||
:am-pm-mode="amPmMode"
|
||||
:spinner-date="parsedValue"
|
||||
:disabled-hours="disabledHours"
|
||||
:disabled-minutes="disabledMinutes"
|
||||
:disabled-seconds="disabledSeconds"
|
||||
@change="handleChange"
|
||||
@set-option="onSetOption"
|
||||
@select-range="setSelectionRange"
|
||||
/>
|
||||
</div>
|
||||
@ -42,12 +46,10 @@ import {
|
||||
ref,
|
||||
computed,
|
||||
inject,
|
||||
provide,
|
||||
PropType,
|
||||
} from 'vue'
|
||||
import { EVENT_CODE } from '@element-plus/utils/aria'
|
||||
import { t } from '@element-plus/locale'
|
||||
import mitt from 'mitt'
|
||||
import TimeSpinner from './basic-time-spinner.vue'
|
||||
import dayjs, { Dayjs } from 'dayjs'
|
||||
import { getAvaliableArrs } from './useTimePicker'
|
||||
@ -59,32 +61,31 @@ export default defineComponent({
|
||||
|
||||
props: {
|
||||
visible: {
|
||||
type: [Boolean],
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
datetimeRole: {
|
||||
type: String,
|
||||
},
|
||||
parsedValue: {
|
||||
type: Dayjs as PropType<Dayjs>,
|
||||
default: '',
|
||||
type: [Object, String] as PropType<string | Dayjs>,
|
||||
},
|
||||
arrowControl: {
|
||||
type: [Boolean],
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
pickerOptions: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['pick', 'select-range'],
|
||||
emits: ['pick', 'select-range', 'set-picker-option'],
|
||||
|
||||
setup(props, ctx) {
|
||||
// data
|
||||
const selectionRange = ref([0, 2])
|
||||
const oldValue = ref(props.parsedValue)
|
||||
// computed
|
||||
const showSeconds = computed(() => {
|
||||
return props.format.includes('ss')
|
||||
@ -101,7 +102,7 @@ export default defineComponent({
|
||||
return parsedDate.isSame(result)
|
||||
}
|
||||
const handleCancel = () => {
|
||||
ctx.emit('pick', '', false, true)
|
||||
ctx.emit('pick', oldValue.value, false)
|
||||
}
|
||||
const handleConfirm = (visible = false, first) => {
|
||||
if (first) return
|
||||
@ -157,11 +158,11 @@ export default defineComponent({
|
||||
let avaliableArr
|
||||
const method = avaliableMap[_]
|
||||
if (_ === 'minute') {
|
||||
avaliableArr = method(result.hour())
|
||||
avaliableArr = method(result.hour(), props.datetimeRole)
|
||||
} else if (_ === 'second') {
|
||||
avaliableArr = method(result.hour(), result.minute())
|
||||
avaliableArr = method(result.hour(), result.minute(), props.datetimeRole)
|
||||
} else {
|
||||
avaliableArr = method()
|
||||
avaliableArr = method(props.datetimeRole)
|
||||
}
|
||||
if (avaliableArr && avaliableArr.length && !avaliableArr.includes(result[_]())) {
|
||||
result = result[_](avaliableArr[0])
|
||||
@ -181,31 +182,30 @@ export default defineComponent({
|
||||
return value.format(props.format)
|
||||
}
|
||||
|
||||
const pickerBase = inject('EP_PICKER_BASE') as any
|
||||
pickerBase.hub.emit('SetPickerOption', ['isValidValue', isValidValue])
|
||||
pickerBase.hub.emit('SetPickerOption', ['formatToString', formatToString])
|
||||
pickerBase.hub.emit('SetPickerOption', ['parseUserInput', parseUserInput])
|
||||
pickerBase.hub.emit('SetPickerOption',['handleKeydown', handleKeydown])
|
||||
pickerBase.hub.emit('SetPickerOption',['getRangeAvaliableTime', getRangeAvaliableTime])
|
||||
const timePickeOptions = {} as any
|
||||
const pickerHub = mitt()
|
||||
pickerHub.on('SetOption', e => {
|
||||
timePickeOptions[e[0]] = e[1]
|
||||
})
|
||||
const getDefaultValue = () => {
|
||||
return dayjs(defaultValue)
|
||||
}
|
||||
|
||||
const { disabledHours, disabledMinutes, disabledSeconds } = pickerBase.props
|
||||
ctx.emit('set-picker-option', ['isValidValue', isValidValue])
|
||||
ctx.emit('set-picker-option', ['formatToString', formatToString])
|
||||
ctx.emit('set-picker-option', ['parseUserInput', parseUserInput])
|
||||
ctx.emit('set-picker-option',['handleKeydown', handleKeydown])
|
||||
ctx.emit('set-picker-option',['getRangeAvaliableTime', getRangeAvaliableTime])
|
||||
ctx.emit('set-picker-option',['getDefaultValue', getDefaultValue])
|
||||
const timePickeOptions = {} as any
|
||||
const onSetOption = e => {
|
||||
timePickeOptions[e[0]] = e[1]
|
||||
}
|
||||
const pickerBase = inject('EP_PICKER_BASE') as any
|
||||
const { disabledHours, disabledMinutes, disabledSeconds, defaultValue } = pickerBase.props
|
||||
const {
|
||||
getAvaliableHours,
|
||||
getAvaliableMinutes,
|
||||
getAvaliableSeconds,
|
||||
} = getAvaliableArrs(disabledHours, disabledMinutes, disabledSeconds)
|
||||
provide('EP_TIMEPICK_PANEL', {
|
||||
hub: pickerHub,
|
||||
methods: {
|
||||
disabledHours, disabledMinutes, disabledSeconds,
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
onSetOption,
|
||||
t,
|
||||
handleConfirm,
|
||||
handleChange,
|
||||
@ -213,6 +213,9 @@ export default defineComponent({
|
||||
amPmMode,
|
||||
showSeconds,
|
||||
handleCancel,
|
||||
disabledHours,
|
||||
disabledMinutes,
|
||||
disabledSeconds,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -20,7 +20,11 @@
|
||||
:am-pm-mode="amPmMode"
|
||||
:arrow-control="arrowControl"
|
||||
:spinner-date="minDate"
|
||||
:disabled-hours="disabledHours_"
|
||||
:disabled-minutes="disabledMinutes_"
|
||||
:disabled-seconds="disabledSeconds_"
|
||||
@change="handleMinChange"
|
||||
@set-option="onSetOption"
|
||||
@select-range="setMinSelectionRange"
|
||||
/>
|
||||
</div>
|
||||
@ -38,7 +42,11 @@
|
||||
:am-pm-mode="amPmMode"
|
||||
:arrow-control="arrowControl"
|
||||
:spinner-date="maxDate"
|
||||
:disabled-hours="disabledHours_"
|
||||
:disabled-minutes="disabledMinutes_"
|
||||
:disabled-seconds="disabledSeconds_"
|
||||
@change="handleMaxChange"
|
||||
@set-option="onSetOption"
|
||||
@select-range="setMaxSelectionRange"
|
||||
/>
|
||||
</div>
|
||||
@ -72,10 +80,8 @@ import {
|
||||
computed,
|
||||
PropType,
|
||||
inject,
|
||||
provide,
|
||||
} from 'vue'
|
||||
import dayjs, { Dayjs } from 'dayjs'
|
||||
import mitt from 'mitt'
|
||||
import union from 'lodash/union'
|
||||
import { t } from '@element-plus/locale'
|
||||
import { EVENT_CODE } from '@element-plus/utils/aria'
|
||||
@ -103,8 +109,7 @@ export default defineComponent({
|
||||
default: false,
|
||||
},
|
||||
parsedValue: {
|
||||
type: Array as PropType<Array<Dayjs>>,
|
||||
default: '',
|
||||
type: [Array, String] as PropType<string | Array<Dayjs>>,
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
@ -112,13 +117,14 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
|
||||
emits: ['pick', 'select-range'],
|
||||
emits: ['pick', 'select-range', 'set-picker-option'],
|
||||
|
||||
setup(props, ctx) {
|
||||
const minDate = computed(() => props.parsedValue[0])
|
||||
const maxDate = computed(() => props.parsedValue[1])
|
||||
const oldValue = ref(props.parsedValue)
|
||||
const handleCancel = () =>{
|
||||
ctx.emit('pick', null, null, true)
|
||||
ctx.emit('pick', oldValue.value, null)
|
||||
}
|
||||
const showSeconds = computed(() => {
|
||||
return props.format.includes('ss')
|
||||
@ -290,31 +296,33 @@ export default defineComponent({
|
||||
return value.format(props.format)
|
||||
}
|
||||
|
||||
const pickerBase = inject('EP_PICKER_BASE') as any
|
||||
pickerBase.hub.emit('SetPickerOption',['formatToString', formatToString])
|
||||
pickerBase.hub.emit('SetPickerOption',['parseUserInput', parseUserInput])
|
||||
pickerBase.hub.emit('SetPickerOption',['isValidValue', isValidValue])
|
||||
pickerBase.hub.emit('SetPickerOption',['handleKeydown', handleKeydown])
|
||||
pickerBase.hub.emit('SetPickerOption',['getRangeAvaliableTime', getRangeAvaliableTime])
|
||||
const getDefaultValue = () => {
|
||||
if (Array.isArray(defaultValue)) {
|
||||
return defaultValue.map(_=> dayjs(_))
|
||||
}
|
||||
return [
|
||||
dayjs(defaultValue),
|
||||
dayjs(defaultValue).add(60,'m'),
|
||||
]
|
||||
}
|
||||
|
||||
ctx.emit('set-picker-option',['formatToString', formatToString])
|
||||
ctx.emit('set-picker-option',['parseUserInput', parseUserInput])
|
||||
ctx.emit('set-picker-option',['isValidValue', isValidValue])
|
||||
ctx.emit('set-picker-option',['handleKeydown', handleKeydown])
|
||||
ctx.emit('set-picker-option',['getDefaultValue', getDefaultValue])
|
||||
ctx.emit('set-picker-option',['getRangeAvaliableTime', getRangeAvaliableTime])
|
||||
|
||||
const timePickeOptions = {} as any
|
||||
const pickerHub = mitt()
|
||||
pickerHub.on('SetOption', e => {
|
||||
const onSetOption = e => {
|
||||
timePickeOptions[e[0]] = e[1]
|
||||
})
|
||||
}
|
||||
|
||||
const { disabledHours, disabledMinutes, disabledSeconds } = pickerBase.props
|
||||
|
||||
provide('EP_TIMEPICK_PANEL', {
|
||||
hub: pickerHub,
|
||||
methods: {
|
||||
disabledHours: disabledHours_,
|
||||
disabledMinutes: disabledMinutes_,
|
||||
disabledSeconds: disabledSeconds_,
|
||||
},
|
||||
})
|
||||
const pickerBase = inject('EP_PICKER_BASE') as any
|
||||
const { disabledHours, disabledMinutes, disabledSeconds, defaultValue } = pickerBase.props
|
||||
|
||||
return {
|
||||
onSetOption,
|
||||
setMaxSelectionRange,
|
||||
setMinSelectionRange,
|
||||
btnConfirmDisabled,
|
||||
@ -329,6 +337,9 @@ export default defineComponent({
|
||||
handleMaxChange,
|
||||
minSelectableRange,
|
||||
maxSelectableRange,
|
||||
disabledHours_,
|
||||
disabledMinutes_,
|
||||
disabledSeconds_,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -2,10 +2,10 @@ export const EVENT_CODE = {
|
||||
tab: 'Tab',
|
||||
enter: 'Enter',
|
||||
space: 'Space',
|
||||
left: 'ArrowLeft',
|
||||
up: 'ArrowUp',
|
||||
right: 'ArrowRight',
|
||||
down: 'ArrowDown',
|
||||
left: 'ArrowLeft', // 37
|
||||
up: 'ArrowUp', // 38
|
||||
right: 'ArrowRight', // 39
|
||||
down: 'ArrowDown', // 40
|
||||
esc: 'Escape',
|
||||
delete: 'Delete',
|
||||
backspace: 'Backspace',
|
||||
|
@ -25,7 +25,9 @@ Basic date picker measured by 'day'.
|
||||
v-model="value2"
|
||||
type="date"
|
||||
placeholder="Pick a day"
|
||||
:picker-options="pickerOptions">
|
||||
:disabled-date="disabledDate"
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -34,31 +36,27 @@ Basic date picker measured by 'day'.
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
disabledDate(time) {
|
||||
return time.getTime() > Date.now();
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'Today',
|
||||
onClick(picker) {
|
||||
picker.$emit('pick', new Date());
|
||||
}
|
||||
}, {
|
||||
text: 'Yesterday',
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24);
|
||||
picker.emit('pick', date);
|
||||
}
|
||||
}, {
|
||||
text: 'A week ago',
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.emit('pick', date);
|
||||
}
|
||||
}]
|
||||
disabledDate(time) {
|
||||
return time.getTime() > Date.now()
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'Today',
|
||||
value: new Date(),
|
||||
}, {
|
||||
text: 'Yesterday',
|
||||
value: (() => {
|
||||
const date = new Date()
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24)
|
||||
return date
|
||||
})(),
|
||||
}, {
|
||||
text: 'A week ago',
|
||||
value: (() => {
|
||||
const date = new Date()
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
|
||||
return date
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: '',
|
||||
};
|
||||
@ -81,7 +79,7 @@ You can choose week, month, year or multiple dates by extending the standard dat
|
||||
<el-date-picker
|
||||
v-model="value1"
|
||||
type="week"
|
||||
format="Week WW"
|
||||
format="[Week] ww"
|
||||
placeholder="Pick a week">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
@ -157,7 +155,8 @@ Picking a date range is supported.
|
||||
range-separator="To"
|
||||
start-placeholder="Start date"
|
||||
end-placeholder="End date"
|
||||
:picker-options="pickerOptions">
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -166,33 +165,31 @@ Picking a date range is supported.
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: 'Last week',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: 'Last month',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: 'Last 3 months',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'Last week',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: 'Last month',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: 'Last 3 months',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
|
||||
return [start, end]
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: ''
|
||||
};
|
||||
@ -230,7 +227,8 @@ Picking a month range is supported.
|
||||
range-separator="To"
|
||||
start-placeholder="Start month"
|
||||
end-placeholder="End month"
|
||||
:picker-options="pickerOptions">
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -239,29 +237,25 @@ Picking a month range is supported.
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: 'This month',
|
||||
onClick(picker) {
|
||||
picker.$emit('pick', [new Date(), new Date()]);
|
||||
}
|
||||
}, {
|
||||
text: 'This year',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date(new Date().getFullYear(), 0);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: 'Last 6 months',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setMonth(start.getMonth() - 6);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'This month',
|
||||
value: [new Date(), new Date()],
|
||||
}, {
|
||||
text: 'This year',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date(new Date().getFullYear(), 0)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: 'Last 6 months',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setMonth(start.getMonth() - 6)
|
||||
return [start, end]
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: ''
|
||||
};
|
||||
@ -286,7 +280,7 @@ If type is `daterange`, `default-value` sets the left side calendar.
|
||||
v-model="value1"
|
||||
type="date"
|
||||
placeholder="Pick a date"
|
||||
default-value="2010-10-01">
|
||||
:default-value="new Date(2010, 9, 1)">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
@ -297,7 +291,7 @@ If type is `daterange`, `default-value` sets the left side calendar.
|
||||
align="right"
|
||||
start-placeholder="Start Date"
|
||||
end-placeholder="End Date"
|
||||
default-value="2010-10-01">
|
||||
:default-value="[new Date(2010, 9, 1), new Date(2010, 10, 1)]">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -358,29 +352,7 @@ Pay attention to capitalization
|
||||
v-model="value1"
|
||||
type="date"
|
||||
placeholder="Pick a Date"
|
||||
format="yyyy/MM/dd">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Use value-format</span>
|
||||
<div class="demonstration">Value: {{ value2 }}</div>
|
||||
<el-date-picker
|
||||
v-model="value2"
|
||||
type="date"
|
||||
placeholder="Pick a Date"
|
||||
format="yyyy/MM/dd"
|
||||
value-format="yyyy-MM-dd">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Timestamp</span>
|
||||
<div class="demonstration">Value:{{ value3 }}</div>
|
||||
<el-date-picker
|
||||
v-model="value3"
|
||||
type="date"
|
||||
placeholder="Pick a Date"
|
||||
format="yyyy/MM/dd"
|
||||
value-format="timestamp">
|
||||
format="YYYY/MM/DD">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -413,7 +385,7 @@ When picking a date range, you can assign the time part for start date and end d
|
||||
type="daterange"
|
||||
start-placeholder="Start date"
|
||||
end-placeholder="End date"
|
||||
:default-time="['00:00:00', '23:59:59']">
|
||||
:default-time="[new Date(2000, 1, 1, 0 , 0,0), new Date(2000, 2, 1, 23 , 59,59)]">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -26,7 +26,9 @@ Date Picker básico por "día".
|
||||
v-model="value2"
|
||||
type="date"
|
||||
placeholder="Pick a day"
|
||||
:picker-options="pickerOptions">
|
||||
:disabled-date="disabledDate"
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -35,31 +37,27 @@ Date Picker básico por "día".
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
disabledDate(time) {
|
||||
return time.getTime() > Date.now();
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'Today',
|
||||
onClick(picker) {
|
||||
picker.$emit('pick', new Date());
|
||||
}
|
||||
}, {
|
||||
text: 'Yesterday',
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24);
|
||||
picker.emit('pick', date);
|
||||
}
|
||||
}, {
|
||||
text: 'A week ago',
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.emit('pick', date);
|
||||
}
|
||||
}]
|
||||
disabledDate(time) {
|
||||
return time.getTime() > Date.now()
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'Today',
|
||||
value: new Date(),
|
||||
}, {
|
||||
text: 'Yesterday',
|
||||
value: (() => {
|
||||
const date = new Date()
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24)
|
||||
return date
|
||||
})(),
|
||||
}, {
|
||||
text: 'A week ago',
|
||||
value: (() => {
|
||||
const date = new Date()
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
|
||||
return date
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: '',
|
||||
};
|
||||
@ -83,7 +81,7 @@ Puede elegir la semana, el mes, el año o varias fechas ampliando el componente
|
||||
<el-date-picker
|
||||
v-model="value1"
|
||||
type="week"
|
||||
format="Week WW"
|
||||
format="[Week] ww"
|
||||
placeholder="Pick a week">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
@ -159,7 +157,8 @@ Se soporta la selección de un rango de fechas.
|
||||
range-separator="To"
|
||||
start-placeholder="Start date"
|
||||
end-placeholder="End date"
|
||||
:picker-options="pickerOptions">
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -168,33 +167,31 @@ Se soporta la selección de un rango de fechas.
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: 'Last week',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: 'Last month',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: 'Last 3 months',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'Last week',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: 'Last month',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: 'Last 3 months',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
|
||||
return [start, end]
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: ''
|
||||
};
|
||||
@ -232,7 +229,8 @@ Se admite la selección de un intervalo de un mes.
|
||||
range-separator="To"
|
||||
start-placeholder="Start month"
|
||||
end-placeholder="End month"
|
||||
:picker-options="pickerOptions">
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -241,29 +239,25 @@ Se admite la selección de un intervalo de un mes.
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: 'This month',
|
||||
onClick(picker) {
|
||||
picker.$emit('pick', [new Date(), new Date()]);
|
||||
}
|
||||
}, {
|
||||
text: 'This year',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date(new Date().getFullYear(), 0);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: 'Last 6 months',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setMonth(start.getMonth() - 6);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'This month',
|
||||
value: [new Date(), new Date()],
|
||||
}, {
|
||||
text: 'This year',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date(new Date().getFullYear(), 0)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: 'Last 6 months',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setMonth(start.getMonth() - 6)
|
||||
return [start, end]
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: ''
|
||||
};
|
||||
@ -288,7 +282,7 @@ Si el tipo es `daterange`, `default-value` establece el calendario del lado izqu
|
||||
v-model="value1"
|
||||
type="date"
|
||||
placeholder="Pick a date"
|
||||
default-value="2010-10-01">
|
||||
:default-value="new Date(2010, 9, 1)">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
@ -299,7 +293,7 @@ Si el tipo es `daterange`, `default-value` establece el calendario del lado izqu
|
||||
align="right"
|
||||
start-placeholder="Start Date"
|
||||
end-placeholder="End Date"
|
||||
default-value="2010-10-01">
|
||||
:default-value="[new Date(2010, 9, 1), new Date(2010, 10, 1)]">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -358,29 +352,7 @@ Preste atención a la capitalización
|
||||
v-model="value1"
|
||||
type="date"
|
||||
placeholder="Pick a Date"
|
||||
format="yyyy/MM/dd">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Use value-format</span>
|
||||
<div class="demonstration">Value: {{ value2 }}</div>
|
||||
<el-date-picker
|
||||
v-model="value2"
|
||||
type="date"
|
||||
placeholder="Pick a Date"
|
||||
format="yyyy/MM/dd"
|
||||
value-format="yyyy-MM-dd">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Timestamp</span>
|
||||
<div class="demonstration">Value:{{ value3 }}</div>
|
||||
<el-date-picker
|
||||
v-model="value3"
|
||||
type="date"
|
||||
placeholder="Pick a Date"
|
||||
format="yyyy/MM/dd"
|
||||
value-format="timestamp">
|
||||
format="YYYY/MM/DD">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -414,7 +386,7 @@ Al seleccionar un intervalo de fechas, puede asignar la hora para la fecha de in
|
||||
type="daterange"
|
||||
start-placeholder="Start date"
|
||||
end-placeholder="End date"
|
||||
:default-time="['00:00:00', '23:59:59']">
|
||||
:default-time="[new Date(2000, 1, 1, 0 , 0,0), new Date(2000, 2, 1, 23 , 59,59)]">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -24,7 +24,9 @@ L'unité de base du DatePicker est le jour.
|
||||
v-model="value2"
|
||||
type="date"
|
||||
placeholder="Choississez un jour"
|
||||
:picker-options="pickerOptions">
|
||||
:disabled-date="disabledDate"
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -33,31 +35,27 @@ L'unité de base du DatePicker est le jour.
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
disabledDate(time) {
|
||||
return time.getTime() > Date.now();
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'Aujourd\'hui',
|
||||
onClick(picker) {
|
||||
picker.$emit('pick', new Date());
|
||||
}
|
||||
}, {
|
||||
text: 'Hier',
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24);
|
||||
picker.emit('pick', date);
|
||||
}
|
||||
}, {
|
||||
text: 'Il y a une semaine',
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.emit('pick', date);
|
||||
}
|
||||
}]
|
||||
disabledDate(time) {
|
||||
return time.getTime() > Date.now()
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'Today',
|
||||
value: new Date(),
|
||||
}, {
|
||||
text: 'Yesterday',
|
||||
value: (() => {
|
||||
const date = new Date()
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24)
|
||||
return date
|
||||
})(),
|
||||
}, {
|
||||
text: 'A week ago',
|
||||
value: (() => {
|
||||
const date = new Date()
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
|
||||
return date
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: '',
|
||||
};
|
||||
@ -80,7 +78,7 @@ Vous pouvez sélectionner une semaine, un mois, une année ou plusieurs dates en
|
||||
<el-date-picker
|
||||
v-model="value1"
|
||||
type="week"
|
||||
format="Week WW"
|
||||
format="[Week] ww"
|
||||
placeholder="Sélectionnez une semaine">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
@ -156,7 +154,8 @@ Vous pouvez sélectionner une plage de dates.
|
||||
range-separator="à"
|
||||
start-placeholder="Date de début"
|
||||
end-placeholder="Date de fin"
|
||||
:picker-options="pickerOptions">
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -165,33 +164,31 @@ Vous pouvez sélectionner une plage de dates.
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: 'Semaine dernière',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: 'Mois dernier',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: 'Trois derniers mois',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'Last week',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: 'Last month',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: 'Last 3 months',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
|
||||
return [start, end]
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: ''
|
||||
};
|
||||
@ -229,7 +226,8 @@ Vous pouvez sélectionner une plage de mois.
|
||||
range-separator="à"
|
||||
start-placeholder="Mois de début"
|
||||
end-placeholder="Mois de fin"
|
||||
:picker-options="pickerOptions">
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -238,29 +236,25 @@ Vous pouvez sélectionner une plage de mois.
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: 'Ce mois',
|
||||
onClick(picker) {
|
||||
picker.$emit('pick', [new Date(), new Date()]);
|
||||
}
|
||||
}, {
|
||||
text: 'Cette année',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date(new Date().getFullYear(), 0);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: 'Les derniers 6 mois',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setMonth(start.getMonth() - 6);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'This month',
|
||||
value: [new Date(), new Date()],
|
||||
}, {
|
||||
text: 'This year',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date(new Date().getFullYear(), 0)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: 'Last 6 months',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setMonth(start.getMonth() - 6)
|
||||
return [start, end]
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: ''
|
||||
};
|
||||
@ -285,7 +279,7 @@ Si le type est `daterange`, `default-value` configure la panneau de gauche.
|
||||
v-model="value1"
|
||||
type="date"
|
||||
placeholder="Sélectionnez une date"
|
||||
default-value="2010-10-01">
|
||||
:default-value="new Date(2010, 9, 1)">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
@ -296,7 +290,7 @@ Si le type est `daterange`, `default-value` configure la panneau de gauche.
|
||||
align="right"
|
||||
start-placeholder="Date de début"
|
||||
end-placeholder="Date de fin"
|
||||
default-value="2010-10-01">
|
||||
:default-value="[new Date(2010, 9, 1), new Date(2010, 10, 1)]">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -358,29 +352,7 @@ Attention à la capitalisation !
|
||||
v-model="value1"
|
||||
type="date"
|
||||
placeholder="Sélectionnez une date"
|
||||
format="yyyy/MM/dd">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Utilise value-format</span>
|
||||
<div class="demonstration">Value: {{ value2 }}</div>
|
||||
<el-date-picker
|
||||
v-model="value2"
|
||||
type="date"
|
||||
placeholder="Sélectionnez une date"
|
||||
format="yyyy/MM/dd"
|
||||
value-format="yyyy-MM-dd">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">Timestamp</span>
|
||||
<div class="demonstration">Value:{{ value3 }}</div>
|
||||
<el-date-picker
|
||||
v-model="value3"
|
||||
type="date"
|
||||
placeholder="Sélectionnez une date"
|
||||
format="yyyy/MM/dd"
|
||||
value-format="timestamp">
|
||||
format="YYYY/MM/DD">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -413,7 +385,7 @@ Lorsque vous choisissez une plage de dates, vous pouvez assigner l'horaire de d
|
||||
type="daterange"
|
||||
start-placeholder="Date de début"
|
||||
end-placeholder="Date de fin"
|
||||
:default-time="['00:00:00', '23:59:59']">
|
||||
:default-time="[new Date(2000, 1, 1, 0 , 0,0), new Date(2000, 2, 1, 23 , 59,59)]">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -25,7 +25,9 @@
|
||||
align="right"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
:picker-options="pickerOptions">
|
||||
:disabled-date="disabledDate"
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -34,31 +36,27 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
disabledDate(time) {
|
||||
return time.getTime() > Date.now();
|
||||
},
|
||||
shortcuts: [{
|
||||
text: '今天',
|
||||
onClick(picker) {
|
||||
picker.$emit('pick', new Date());
|
||||
}
|
||||
}, {
|
||||
text: '昨天',
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24);
|
||||
picker.emit('pick', date);
|
||||
}
|
||||
}, {
|
||||
text: '一周前',
|
||||
onClick(picker) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.emit('pick', date);
|
||||
}
|
||||
}]
|
||||
disabledDate(time) {
|
||||
return time.getTime() > Date.now()
|
||||
},
|
||||
shortcuts: [{
|
||||
text: 'Today',
|
||||
value: new Date(),
|
||||
}, {
|
||||
text: 'Yesterday',
|
||||
value: (() => {
|
||||
const date = new Date()
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24)
|
||||
return date
|
||||
})(),
|
||||
}, {
|
||||
text: 'A week ago',
|
||||
value: (() => {
|
||||
const date = new Date()
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)
|
||||
return date
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: '',
|
||||
};
|
||||
@ -80,7 +78,7 @@
|
||||
<el-date-picker
|
||||
v-model="value1"
|
||||
type="week"
|
||||
format="yyyy 第 WW 周"
|
||||
format="gggg 第 ww 周"
|
||||
placeholder="选择周">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
@ -154,7 +152,8 @@
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:picker-options="pickerOptions">
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -163,33 +162,31 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: '最近一周',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近一个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近三个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
shortcuts: [{
|
||||
text: '最近一周',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: '最近一个月',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: '最近三个月',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
|
||||
return [start, end]
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: ''
|
||||
};
|
||||
@ -227,7 +224,8 @@
|
||||
range-separator="至"
|
||||
start-placeholder="开始月份"
|
||||
end-placeholder="结束月份"
|
||||
:picker-options="pickerOptions">
|
||||
:shortcuts="shortcuts"
|
||||
>
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -236,29 +234,25 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pickerOptions: {
|
||||
shortcuts: [{
|
||||
text: '本月',
|
||||
onClick(picker) {
|
||||
picker.$emit('pick', [new Date(), new Date()]);
|
||||
}
|
||||
}, {
|
||||
text: '今年至今',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date(new Date().getFullYear(), 0);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}, {
|
||||
text: '最近六个月',
|
||||
onClick(picker) {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setMonth(start.getMonth() - 6);
|
||||
picker.$emit('pick', [start, end]);
|
||||
}
|
||||
}]
|
||||
},
|
||||
shortcuts: [{
|
||||
text: '本月',
|
||||
value: [new Date(), new Date()],
|
||||
}, {
|
||||
text: '今年至今',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date(new Date().getFullYear(), 0)
|
||||
return [start, end]
|
||||
})(),
|
||||
}, {
|
||||
text: '最近六个月',
|
||||
value: (() => {
|
||||
const end = new Date()
|
||||
const start = new Date()
|
||||
start.setMonth(start.getMonth() - 6)
|
||||
return [start, end]
|
||||
})(),
|
||||
}],
|
||||
value1: '',
|
||||
value2: ''
|
||||
};
|
||||
@ -268,6 +262,49 @@
|
||||
```
|
||||
:::
|
||||
|
||||
### Default Value (需要翻译)
|
||||
|
||||
If user hasn't picked a date, shows today's calendar by default. You can use `default-value` to set another date. Its value should be parsable by `new Date()`.
|
||||
|
||||
If type is `daterange`, `default-value` sets the left side calendar.
|
||||
|
||||
:::demo
|
||||
```html
|
||||
<template>
|
||||
<div class="block">
|
||||
<span class="demonstration">date</span>
|
||||
<el-date-picker
|
||||
v-model="value1"
|
||||
type="date"
|
||||
placeholder="Pick a date"
|
||||
:default-value="new Date(2010, 9, 1)">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">daterange</span>
|
||||
<el-date-picker
|
||||
v-model="value2"
|
||||
type="daterange"
|
||||
align="right"
|
||||
start-placeholder="Start Date"
|
||||
end-placeholder="End Date"
|
||||
:default-value="[new Date(2010, 9, 1), new Date(2010, 10, 1)]">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
value1: '',
|
||||
value2: ''
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### 日期格式
|
||||
|
||||
@ -311,29 +348,7 @@
|
||||
v-model="value1"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="yyyy 年 MM 月 dd 日">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">使用 value-format</span>
|
||||
<div class="demonstration">值:{{ value2 }}</div>
|
||||
<el-date-picker
|
||||
v-model="value2"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="yyyy 年 MM 月 dd 日"
|
||||
value-format="yyyy-MM-dd">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">时间戳</span>
|
||||
<div class="demonstration">值:{{ value3 }}</div>
|
||||
<el-date-picker
|
||||
v-model="value3"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
format="yyyy 年 MM 月 dd 日"
|
||||
value-format="timestamp">
|
||||
format="YYYY 年 MM 月 DD 日">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
@ -366,7 +381,7 @@
|
||||
type="daterange"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:default-time="['00:00:00', '23:59:59']">
|
||||
:default-time="[new Date(2000, 1, 1, 0 , 0,0), new Date(2000, 2, 1, 23 , 59,59)]">
|
||||
</el-date-picker>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,14 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
change me
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
}
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user