Skip to content

Commit 230e09f

Browse files
fix: 🐛 修复 DateTimePicker 区域选择时边界值处理错误的问题
1 parent 34a4878 commit 230e09f

1 file changed

Lines changed: 137 additions & 133 deletions

File tree

src/uni_modules/wot-design-uni/components/wd-datetime-picker/wd-datetime-picker.vue

Lines changed: 137 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
>
88
<!--文案-->
99
<view class="wd-picker__field" @click="showPopup">
10-
<slot v-if="useDefaultSlot"></slot>
10+
<slot v-if="$slots.default"></slot>
1111
<view v-else :class="['wd-picker__cell', customCellClass]">
1212
<view
13-
v-if="label || useLabelSlot"
13+
v-if="label || $slots.label"
1414
:class="`wd-picker__label ${customLabelClass} ${isRequired ? 'is-required' : ''}`"
1515
:style="labelWidth ? 'min-width:' + labelWidth + ';max-width:' + labelWidth + ';' : ''"
1616
>
17-
<block v-if="label">{{ label }}</block>
18-
<slot v-else name="label"></slot>
17+
<slot v-if="$slots.label" name="label"></slot>
18+
<block v-else>{{ label }}</block>
1919
</view>
2020
<view class="wd-picker__body">
2121
<view class="wd-picker__value-wraper">
@@ -319,33 +319,105 @@ const isRequired = computed(() => {
319319
})
320320
321321
/**
322-
* @description 自定义列项筛选规则,对每列单项进行禁用校验,最终返回传入PickerView的columns数组
323-
* @param {Component} picker datetimePickerView对象
324-
* @return {Array} columns
322+
* @description 处理时间边界值判断
323+
* @param isStart 是否是开始时间
324+
* @param columnType 当前列类型
325+
* @param value 当前值
326+
* @param currentArray 当前完整选择的数组
327+
* @param boundary 边界值数组
328+
* @returns 是否超出边界
325329
*/
326-
const customColumnFormatter: DatetimePickerViewColumnFormatter = (picker) => {
327-
if (!picker) {
328-
return []
330+
function handleBoundaryValue(
331+
isStart: boolean,
332+
columnType: DatetimePickerViewColumnType,
333+
value: number,
334+
currentArray: number[],
335+
boundary: number[]
336+
): boolean {
337+
const { type } = props
338+
339+
switch (type) {
340+
case 'datetime': {
341+
const [year, month, date, hour, minute] = boundary
342+
if (columnType === 'year') {
343+
return isStart ? value > year : value < year
344+
}
345+
if (columnType === 'month' && currentArray[0] === year) {
346+
return isStart ? value > month : value < month
347+
}
348+
if (columnType === 'date' && currentArray[0] === year && currentArray[1] === month) {
349+
return isStart ? value > date : value < date
350+
}
351+
if (columnType === 'hour' && currentArray[0] === year && currentArray[1] === month && currentArray[2] === date) {
352+
return isStart ? value > hour : value < hour
353+
}
354+
if (columnType === 'minute' && currentArray[0] === year && currentArray[1] === month && currentArray[2] === date && currentArray[3] === hour) {
355+
return isStart ? value > minute : value < minute
356+
}
357+
break
358+
}
359+
case 'year-month': {
360+
const [year, month] = boundary
361+
if (columnType === 'year') {
362+
return isStart ? value > year : value < year
363+
}
364+
if (columnType === 'month' && currentArray[0] === year) {
365+
return isStart ? value > month : value < month
366+
}
367+
break
368+
}
369+
case 'year': {
370+
const [year] = boundary
371+
if (columnType === 'year') {
372+
return isStart ? value > year : value < year
373+
}
374+
break
375+
}
376+
case 'date': {
377+
const [year, month, date] = boundary
378+
if (columnType === 'year') {
379+
return isStart ? value > year : value < year
380+
}
381+
if (columnType === 'month' && currentArray[0] === year) {
382+
return isStart ? value > month : value < month
383+
}
384+
if (columnType === 'date' && currentArray[0] === year && currentArray[1] === month) {
385+
return isStart ? value > date : value < date
386+
}
387+
break
388+
}
389+
case 'time': {
390+
const [hour, minute] = boundary
391+
if (columnType === 'hour') {
392+
return isStart ? value > hour : value < hour
393+
}
394+
if (columnType === 'minute' && currentArray[0] === hour) {
395+
return isStart ? value > minute : value < minute
396+
}
397+
break
398+
}
329399
}
400+
return false
401+
}
402+
403+
/**
404+
* @description 自定义列项筛选规则
405+
*/
406+
const customColumnFormatter: DatetimePickerViewColumnFormatter = (picker) => {
407+
if (!picker) return []
408+
330409
const { type } = props
331410
const { startSymbol, formatter } = picker
332-
// 校准上下方picker的value值,与内部innerValue对应
333411
const start = picker.correctValue(innerValue.value)
334412
const end = picker.correctValue(endInnerValue.value)
335413
336-
/**
337-
* 如果是上方picekr 那么将下方picker的值作为下边界
338-
* 如果是下方picekr 那么将上方picker的值作为上边界
339-
*/
340414
const currentValue = startSymbol ? picker.getPickerValue(start, type) : picker.getPickerValue(end, type)
341415
const boundary = startSymbol ? picker.getPickerValue(end, type) : picker.getPickerValue(start, type)
342-
// 获取当前picekr中的源列数组
343416
const columns = picker.getOriginColumns()
344417
345-
// 此时index是最外层知道当前的索引即可得到当前是哪个时间段
346-
return columns.map((column, cIndex) => {
418+
return columns.map((column, _) => {
347419
return column.values.map((value) => {
348-
const disabled = columnDisabledRules(startSymbol, columns, cIndex, value, currentValue, boundary)
420+
const disabled = handleBoundaryValue(startSymbol, column.type, value, currentValue, boundary)
349421
return {
350422
label: formatter ? formatter(column.type, padZero(value)) : padZero(value),
351423
value,
@@ -415,9 +487,6 @@ function close() {
415487
onCancel()
416488
}
417489
418-
/**
419-
* @description 展示popup,小程序有个bug,在picker-view弹出时设置value,会触发change事件,而且会将picker-view的value多次触发change重置为第一项
420-
*/
421490
function showPopup() {
422491
if (props.disabled || props.readonly) return
423492
@@ -450,15 +519,34 @@ function tabChange() {
450519
* @description datetimePickerView change 事件
451520
*/
452521
function onChangeStart({ value }: { value: number | string }) {
453-
innerValue.value = deepClone(value)
522+
if (!datetimePickerView.value) return
523+
if (region.value && !datetimePickerView1.value) return
524+
454525
if (region.value) {
455-
showTabLabel.value = [setTabLabel(), deepClone(showTabLabel.value[1])]
456-
emit('change', {
457-
value: [value, endInnerValue.value]
526+
// 区间选择才需要处理边界值
527+
const currentArray = datetimePickerView.value.getPickerValue(value, props.type)
528+
const boundaryArray = datetimePickerView.value.getPickerValue(endInnerValue.value, props.type)
529+
const columns = datetimePickerView.value.getOriginColumns()
530+
531+
// 检查是否有任何列超出边界
532+
const needsAdjust = columns.some((column, index) => {
533+
return handleBoundaryValue(true, column.type, currentArray[index], currentArray, boundaryArray)
534+
})
535+
536+
innerValue.value = deepClone(needsAdjust ? endInnerValue.value : value)
537+
538+
nextTick(() => {
539+
showTabLabel.value = [setTabLabel(), deepClone(showTabLabel.value[1])]
540+
emit('change', {
541+
value: [innerValue.value, endInnerValue.value]
542+
})
543+
// 更新两个picker的列
544+
datetimePickerView.value && datetimePickerView.value.setColumns(datetimePickerView.value.updateColumns())
545+
datetimePickerView1.value && datetimePickerView1.value.setColumns(datetimePickerView1.value.updateColumns())
458546
})
459-
datetimePickerView.value && datetimePickerView.value.setColumns(datetimePickerView.value.updateColumns())
460-
datetimePickerView1.value && datetimePickerView1.value.setColumns(datetimePickerView1.value.updateColumns())
461547
} else {
548+
// 非区间选择直接设置值即可
549+
innerValue.value = deepClone(value)
462550
emit('change', {
463551
value: innerValue.value
464552
})
@@ -469,13 +557,28 @@ function onChangeStart({ value }: { value: number | string }) {
469557
* @description 区域选择 下方 datetimePickerView change 事件
470558
*/
471559
function onChangeEnd({ value }: { value: number | string }) {
472-
endInnerValue.value = deepClone(value)
473-
showTabLabel.value = [deepClone(showTabLabel.value[0]), setTabLabel(1)]
474-
emit('change', {
475-
value: [innerValue.value, value]
560+
if (!datetimePickerView.value || !datetimePickerView1.value) return
561+
562+
const currentArray = datetimePickerView1.value.getPickerValue(value, props.type)
563+
const boundaryArray = datetimePickerView1.value.getPickerValue(innerValue.value, props.type)
564+
const columns = datetimePickerView1.value.getOriginColumns()
565+
566+
// 检查是否有任何列超出边界
567+
const needsAdjust = columns.some((column, index) => {
568+
return handleBoundaryValue(false, column.type, currentArray[index], currentArray, boundaryArray)
569+
})
570+
571+
endInnerValue.value = deepClone(needsAdjust ? innerValue.value : value)
572+
573+
nextTick(() => {
574+
showTabLabel.value = [deepClone(showTabLabel.value[0]), setTabLabel(1)]
575+
emit('change', {
576+
value: [innerValue.value, endInnerValue.value]
577+
})
578+
// 更新两个picker的列
579+
datetimePickerView.value && datetimePickerView.value.setColumns(datetimePickerView.value.updateColumns())
580+
datetimePickerView1.value && datetimePickerView1.value.setColumns(datetimePickerView1.value.updateColumns())
476581
})
477-
datetimePickerView.value && datetimePickerView.value.setColumns(datetimePickerView.value.updateColumns())
478-
datetimePickerView1.value && datetimePickerView1.value.setColumns(datetimePickerView1.value.updateColumns())
479582
}
480583
481584
/**
@@ -620,11 +723,6 @@ function defaultDisplayFormat(items: Record<string, any>[], tabLabel: boolean =
620723
621724
// 如果使用了自定义的的formatter,defaultDisplayFormat无效
622725
if (props.formatter) {
623-
/**
624-
* 不建议使用 this.picker.picker.getLabels() 拉取
625-
* 在初始展示时,需要使用模拟 nextTick 来等待内部 pickerView 渲染后labels才可得到format后的labels
626-
* 但使用模拟nextTick会造成页面延迟展示问题,对用户感知来讲不友好,因此不适用该方法
627-
*/
628726
const typeMaps = {
629727
year: ['year'],
630728
datetime: ['year', 'month', 'date', 'hour', 'minute'],
@@ -653,100 +751,6 @@ function defaultDisplayFormat(items: Record<string, any>[], tabLabel: boolean =
653751
}
654752
}
655753
656-
/**
657-
* @description 区域选择time禁用规则,根据传入的位置标志以及日期类型 返回该节点是否禁用
658-
* @param {Boolean} isStart 时间段类型 true:start | false:end
659-
* @param {Array} column 当前遍历到的列数组
660-
* @param {Number} cindex 外层column的索引(对应每一个类型)
661-
* @param {Number / String} value 遍历到的当前值
662-
* @param {Array} currentValue 当前选中的值 this.pickerValue
663-
* @param {Array} boundary 当前变量的限制值,决定禁用的边界值
664-
* @return {Boolean} disabled
665-
*/
666-
function columnDisabledRules(
667-
isStart: boolean,
668-
columns: {
669-
type: DatetimePickerViewColumnType
670-
values: number[]
671-
}[],
672-
cIndex: number,
673-
value: number,
674-
currentValue: number[],
675-
boundary: number[]
676-
) {
677-
const { type } = props
678-
// 0年 1月 2日 3時 4分
679-
// startPicker 除最小值外 还需要有一个时间限制, endPicker 时间选择后, startPicker 的 添加一个时间限制boundary min->boundary
680-
// endPicker 除最小值外 还需要有一个时间限制, startPicker 时间选择后, endPicker 的 添加一个时间限制boundary boundary->max
681-
const column = columns[cIndex]
682-
// 根据当前选择年确认 ranges[0][0] minYear ranges[0][1] maxYear 以此类推
683-
if (type === 'datetime') {
684-
const year = boundary[0]
685-
const month = boundary[1]
686-
const date = boundary[2]
687-
const hour = boundary[3]
688-
const minute = boundary[4]
689-
690-
if (column.type === 'year') {
691-
return isStart ? value > year : value < year
692-
}
693-
if (column.type === 'month' && currentValue[0] === year) {
694-
return isStart ? value > month : value < month
695-
}
696-
if (column.type === 'date' && currentValue[0] === year && currentValue[1] === month) {
697-
return isStart ? value > date : value < date
698-
}
699-
if (column.type === 'hour' && currentValue[0] === year && currentValue[1] === month && currentValue[2] === date) {
700-
return isStart ? value > hour : value < hour
701-
}
702-
if (column.type === 'minute' && currentValue[0] === year && currentValue[1] === month && currentValue[2] === date && currentValue[3] === hour) {
703-
return isStart ? value > minute : value < minute
704-
}
705-
} else if (type === 'year-month') {
706-
const year = boundary[0]
707-
const month = boundary[1]
708-
709-
if (column.type === 'year') {
710-
return isStart ? value > year : value < year
711-
}
712-
if (column.type === 'month' && currentValue[0] === year) {
713-
return isStart ? value > month : value < month
714-
}
715-
} else if (type === 'year') {
716-
const year = boundary[0]
717-
718-
if (column.type === 'year') {
719-
return isStart ? value > year : value < year
720-
}
721-
} else if (type === 'date') {
722-
const year = boundary[0]
723-
const month = boundary[1]
724-
const date = boundary[2]
725-
726-
if (column.type === 'year') {
727-
return isStart ? value > year : value < year
728-
}
729-
if (column.type === 'month' && currentValue[0] === year) {
730-
return isStart ? value > month : value < month
731-
}
732-
if (column.type === 'date' && currentValue[0] === year && currentValue[1] === month) {
733-
return isStart ? value > date : value < date
734-
}
735-
} else if (type === 'time') {
736-
const hour = boundary[0]
737-
const minute = boundary[1]
738-
739-
if (column.type === 'hour') {
740-
return isStart ? value > hour : value < hour
741-
}
742-
if (column.type === 'minute' && currentValue[0] === hour) {
743-
return isStart ? value > minute : value < minute
744-
}
745-
}
746-
747-
return false
748-
}
749-
750754
function setLoading(loading: boolean) {
751755
isLoading.value = loading
752756
}

0 commit comments

Comments
 (0)