Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(date-picker): [date-picker] date picker add quarter type #1513

Merged
merged 10 commits into from
Mar 30, 2024
2 changes: 1 addition & 1 deletion examples/sites/demos/apis/date-picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ interface IPickerOptions {
name: 'IType',
type: 'type',
code: `
type IType = 'date' | 'dates' | 'daterange' | 'datetime' | 'datetimerange' | 'week' | 'month' | 'monthrange' | 'year' | 'years' | 'yearrange'
type IType = 'date' | 'dates' | 'daterange' | 'datetime' | 'datetimerange' | 'week' | 'month' | 'monthrange' | 'quarter' | 'year' | 'years' | 'yearrange'
`
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<tiny-date-picker v-model="dateTimeValue" type="datetime" placeholder="请选择日期"></tiny-date-picker>
<tiny-date-picker v-model="weekValue" type="week" placeholder="请选择周"></tiny-date-picker>
<tiny-date-picker v-model="monthValue" type="month" placeholder="请选择月份"></tiny-date-picker>
<tiny-date-picker v-model="quarterValue" type="quarter" placeholder="请选择季度"></tiny-date-picker>
<tiny-date-picker v-model="yearValue" type="year" placeholder="请选择年份"></tiny-date-picker>
</div>
</template>
Expand All @@ -16,6 +17,7 @@ const value = ref('')
const dateTimeValue = ref('')
const weekValue = ref('')
const monthValue = ref('')
const quarterValue = ref('')
const yearValue = ref('')
</script>

Expand Down
2 changes: 2 additions & 0 deletions examples/sites/demos/pc/app/date-picker/basic-usage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<tiny-date-picker v-model="dateTimeValue" type="datetime" placeholder="请选择日期"></tiny-date-picker>
<tiny-date-picker v-model="weekValue" type="week" placeholder="请选择周"></tiny-date-picker>
<tiny-date-picker v-model="monthValue" type="month" placeholder="请选择月份"></tiny-date-picker>
<tiny-date-picker v-model="quarterValue" type="quarter" placeholder="请选择季度"></tiny-date-picker>
<tiny-date-picker v-model="yearValue" type="year" placeholder="请选择年份"></tiny-date-picker>
</div>
</template>
Expand All @@ -21,6 +22,7 @@ export default {
dateTimeValue: '',
weekValue: '',
monthValue: '',
quarterValue: '',
yearValue: ''
}
}
Expand Down
4 changes: 2 additions & 2 deletions examples/sites/demos/pc/app/date-picker/default-value.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ test('[DatePicker] 测试选择器打开时默认时间设置', async ({ page })
await dateInputDefaultTime.press('Enter')

await page.getByRole('textbox', { name: '2023-05-20 09:00:00' }).click()
await page.getByRole('cell', { name: '15' }).getByText('15').click()
await page.getByRole('cell', { name: '15' }).getByText('15').last().click()
await expect(page.getByRole('textbox', { name: '选择时间' })).toHaveValue('09:00:00')

await page.getByRole('textbox').nth(3).click()
await page.getByRole('cell', { name: '10' }).getByText('10').first().click()
await page.getByRole('cell', { name: '10' }).getByText('10').last().click()
await page.getByRole('cell', { name: '10' }).getByText('10').nth(1).click()
await expect(page.getByRole('textbox', { name: '开始时间' })).toHaveValue('09:00:00')
await expect(page.getByRole('textbox', { name: '结束时间' })).toHaveValue('18:00:00')
Expand Down
6 changes: 3 additions & 3 deletions examples/sites/demos/pc/app/date-picker/events.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ test('[DatePicker] 测试事件', async ({ page }) => {
.filter({ hasText: /^blur:$/ })
.getByRole('textbox')
.click()
await page.getByRole('cell', { name: '15' }).getByText('15').click()
await page.getByRole('cell', { name: '15' }).getByText('15').last().click()
const blurEventMessageDom = page.locator('div').filter({ hasText: '触发 blur 事件' }).nth(1)
await expect(blurEventMessageDom).toBeVisible()

Expand All @@ -33,13 +33,13 @@ test('[DatePicker] 测试事件', async ({ page }) => {
.filter({ hasText: /^change:$/ })
.getByRole('textbox')
.click()
await page.getByRole('cell', { name: '15' }).getByText('15').click()
await page.getByRole('cell', { name: '15' }).getByText('15').last().click()
const changeEventMessageDom = page.locator('div').filter({ hasText: '触发 change 事件,组件绑定值为:' }).nth(1)
await expect(changeEventMessageDom).toBeVisible()

// onPick 事件
await page.locator('div').filter({ hasText: /^-$/ }).click()
await page.getByRole('cell', { name: '10' }).getByText('10').first().click()
await page.getByRole('cell', { name: '10' }).getByText('10').last().click()
const onPickEventMessageDom = page.locator('div').filter({ hasText: '触发 onPick 事件,开始日期为:' }).nth(1)
await expect(onPickEventMessageDom).toBeVisible()
})
4 changes: 2 additions & 2 deletions examples/sites/demos/pc/app/date-picker/format.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ test('[DatePicker] 测试日期格式化', async ({ page }) => {

// format: 日期输入框中显示的格式
await page.getByRole('textbox', { name: '2023 年 05 月 24 日' }).first().click()
await page.getByRole('cell', { name: '20' }).getByText('20').click()
await page.getByRole('cell', { name: '20' }).getByText('20').last().click()
await expect(page.getByRole('textbox', { name: '2023 年 05 月 20 日' }).first()).toBeVisible()

// time-format: 时间输入框中显示的格式
Expand All @@ -17,6 +17,6 @@ test('[DatePicker] 测试日期格式化', async ({ page }) => {

// value-format: 选中值的格式
await page.locator('.tiny-date-editor input').nth(2).click()
await page.getByRole('cell', { name: '20' }).getByText('20').click()
await page.getByRole('cell', { name: '20' }).getByText('20').last().click()
await expect(page.locator('.select-date')).toHaveText(`当前选中时间:${1589904000000}`)
})
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"pnpm": ">=6.35"
},
"scripts": {
"preinstall": "npx only-allow pnpm",
"preinstall": "node -v && pnpm -v && npx only-allow pnpm",
"postinstall": "pnpm build:internals",
"prepare": "husky install",
"bootstrap": "pnpm --filter=\"!./packages/dist/**\" install",
Expand Down
5 changes: 5 additions & 0 deletions packages/modules.json
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,11 @@
"type": "template",
"exclude": false
},
"QuarterPanel": {
"path": "vue/src/quarter-panel/src/pc.vue",
"type": "template",
"exclude": false
},
"Dept": {
"path": "vue/src/dept/index.ts",
"type": "component",
Expand Down
15 changes: 14 additions & 1 deletion packages/renderless/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export const DATE = {
}

const TriggerTypes =
'date,datetime,time,time-select,week,month,year,years,yearrange,daterange,monthrange,timerange,datetimerange,dates'
'date,datetime,time,time-select,week,month,year,years,yearrange,daterange,monthrange,timerange,datetimerange,dates,quarter'

export const DATEPICKER = {
Day: 'day',
Expand Down Expand Up @@ -167,6 +167,18 @@ export const DATEPICKER = {
center: 'bottom',
right: 'bottom-end'
},
QuarterMap: {
0: 0,
1: 3,
2: 6,
3: 9
},
MonthQuarterMap: {
0: 1,
3: 2,
6: 3,
9: 4
},
TriggerTypes: TriggerTypes.split(','),
DateFormats: {
year: 'yyyy',
Expand All @@ -184,6 +196,7 @@ export const DATEPICKER = {
},
Time: 'time',
TimeRange: 'timerange',
Quarter: 'quarter',
IconTime: 'icon-time',
IconDate: 'icon-Calendar',
DateRange: 'daterange',
Expand Down
19 changes: 17 additions & 2 deletions packages/renderless/src/picker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,16 @@ import globalTimezone from './timezone'
const iso8601Reg = /^\d{4}-\d{2}-\d{2}(.)\d{2}:\d{2}:\d{2}(.+)$/

export const getPanel =
({ DatePanel, DateRangePanel, MonthRangePanel, YearRangePanel, TimePanel, TimeRangePanel, TimeSelect }) =>
({
DatePanel,
DateRangePanel,
MonthRangePanel,
YearRangePanel,
TimePanel,
TimeRangePanel,
QuarterPanel,
TimeSelect
}) =>
(type) => {
if (type === DATEPICKER.DateRange || type === DATEPICKER.DateTimeRange) {
return DateRangePanel
Expand All @@ -35,6 +44,8 @@ export const getPanel =
return TimePanel
} else if (type === DATEPICKER.TimeSelect) {
return TimeSelect
} else if (type === DATEPICKER.Quarter) {
return QuarterPanel
}

return DatePanel
Expand Down Expand Up @@ -413,7 +424,11 @@ export const typeValueResolveMap =
years: getDatesOfTypeValueResolveMap(api),
yearrange: getDatesOfTypeValueResolveMap(api),
number: getNumberOfTypeValueResolveMap(),
dates: getDatesOfTypeValueResolveMap(api)
dates: getDatesOfTypeValueResolveMap(api),
quarter: {
formatter: (value) => `${value.getFullYear()}-Q${DATEPICKER.MonthQuarterMap[value.getMonth()]}`,
parser: api.dateParser
}
})

export const firstInputId =
Expand Down
81 changes: 81 additions & 0 deletions packages/renderless/src/quarter-panel/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { modifyDate, nextYear, prevYear } from '../common/deps/date-util'
import { DATEPICKER } from '../common'

const getTarget = (event) => {
let target = event.target
const tagName = target.tagName

if (tagName === 'A') {
target = target.parentNode.parentNode
}

if (tagName === 'DIV') {
target = target.parentNode
}

if (target.tagName !== 'TD') {
return
}

return target
}

export const handleQuarterTableClick =
({ state, emit }) =>
(event) => {
const target = getTarget(event)
const currentDate = new Date(state.date.getFullYear(), DATEPICKER.QuarterMap[target.cellIndex], 1)
state.value = currentDate
emit('pick', currentDate)
}

export const showYearPicker =
({ state }) =>
() =>
(state.currentView = DATEPICKER.Year)

export const cusPrevYear =
({ state }) =>
() => {
if (state.currentView === DATEPICKER.Year) {
state.startYear = state.startYear - DATEPICKER.PanelYearNum
} else {
state.date = prevYear(state.date)
}
}

export const cusNextYear =
({ state }) =>
() => {
if (state.currentView === DATEPICKER.Year) {
state.startYear = state.startYear + DATEPICKER.PanelYearNum
} else {
state.date = nextYear(state.date)
}
}

export const handleYearPick =
({ state }) =>
(value) => {
state.currentView = DATEPICKER.Quarter
state.date = modifyDate(state.date, value, state.date.getMonth(), state.date.getDate())
}

export const getYearLabel =
({ state, t }) =>
() => {
return state.date.getFullYear()
}

export const getCellStyle =
({ api, props, state }) =>
(cell) => {
const year = state.date.getFullYear()
const quarter = cell.text.slice(1) - 1

const style = {}
style.current =
state.value && state.value.getFullYear() === year && state.value.getMonth() === DATEPICKER.QuarterMap[quarter]

return style
}
46 changes: 46 additions & 0 deletions packages/renderless/src/quarter-panel/vue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { DATEPICKER } from '../common'
import {
handleQuarterTableClick,
showYearPicker,
handleYearPick,
cusPrevYear,
cusNextYear,
getYearLabel,
getCellStyle
} from './index'

export const api = [
'state',
'handleQuarterTableClick',
'showYearPicker',
'handleYearPick',
'cusPrevYear',
'cusNextYear',
'getCellStyle'
]

export const renderless = (props, { reactive, computed }, { emit, t }) => {
const api = {}

const state = reactive({
date: new Date(),
visible: false,
currentView: DATEPICKER.Quarter,
yearLabel: computed(() => api.getYearLabel()),
startYear: Math.floor(new Date().getFullYear() / 10) * 10,
rows: [{ text: 'Q1' }, { text: 'Q2' }, { text: 'Q3' }, { text: 'Q4' }]
})

Object.assign(api, {
state,
handleQuarterTableClick: handleQuarterTableClick({ state, emit }),
showYearPicker: showYearPicker({ state }),
handleYearPick: handleYearPick({ state }),
cusPrevYear: cusPrevYear({ state }),
cusNextYear: cusNextYear({ state }),
getYearLabel: getYearLabel({ state, t }),
getCellStyle: getCellStyle({ api, props, state })
})

return api
}
35 changes: 35 additions & 0 deletions packages/theme/src/quarter-panel/index.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@import '../custom.less';
@import './vars.less';
@import '../month-table/index.less';
@import '../month-table/vars.less';
@import '../date-table/vars.less';

@quarter-panel-prefix-cls: ~'@{css-prefix}quarter-panel';

.@{quarter-panel-prefix-cls} {
.component-css-vars-quarter-panel();

table {
table-layout: fixed;
width: 100%;
}

&__header {
margin: 12px 12px 0 12px;
text-align: center;
padding-bottom: 12px;
border-bottom: 1px solid var(--ti-date-picker-border-color);
line-height: var(--ti-date-picker-header-line-height);
}

&__content {

}

&__table {
.component-css-vars-month-table();
.component-css-vars-date-table();

.month-table();
}
}
1 change: 1 addition & 0 deletions packages/theme/src/quarter-panel/vars.less
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.component-css-vars-quarter-panel() {}
2 changes: 1 addition & 1 deletion packages/theme/src/theme.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default {
'ip-address': 'ip-address',
'link-menu': 'link-menu',
'month-range': 'month-range',
'month-table': 'month-table,year-table',
'month-table': 'month-table,year-table,quarter-panel__table',
'nav-menu': 'nav-menu',
'option-group': 'option-group',
'popup-horiz-menu': 'popup-horiz-menu',
Expand Down
Loading
Loading