From 230e09ff2ac25550b0efc2628827b70162041aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=8D=E5=A6=82=E6=91=B8=E9=B1=BC=E5=8E=BB?= <1780903673@qq.com> Date: Thu, 20 Mar 2025 13:20:02 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=90=9B=20=E4=BF=AE=E5=A4=8D=20Date?= =?UTF-8?q?TimePicker=20=E5=8C=BA=E5=9F=9F=E9=80=89=E6=8B=A9=E6=97=B6?= =?UTF-8?q?=E8=BE=B9=E7=95=8C=E5=80=BC=E5=A4=84=E7=90=86=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wd-datetime-picker/wd-datetime-picker.vue | 270 +++++++++--------- 1 file changed, 137 insertions(+), 133 deletions(-) diff --git a/src/uni_modules/wot-design-uni/components/wd-datetime-picker/wd-datetime-picker.vue b/src/uni_modules/wot-design-uni/components/wd-datetime-picker/wd-datetime-picker.vue index f92e3109..26d950a4 100644 --- a/src/uni_modules/wot-design-uni/components/wd-datetime-picker/wd-datetime-picker.vue +++ b/src/uni_modules/wot-design-uni/components/wd-datetime-picker/wd-datetime-picker.vue @@ -7,15 +7,15 @@ > - + - {{ label }} - + + {{ label }} @@ -319,33 +319,105 @@ const isRequired = computed(() => { }) /** - * @description 自定义列项筛选规则,对每列单项进行禁用校验,最终返回传入PickerView的columns数组 - * @param {Component} picker datetimePickerView对象 - * @return {Array} columns + * @description 处理时间边界值判断 + * @param isStart 是否是开始时间 + * @param columnType 当前列类型 + * @param value 当前值 + * @param currentArray 当前完整选择的数组 + * @param boundary 边界值数组 + * @returns 是否超出边界 + */ +function handleBoundaryValue( + isStart: boolean, + columnType: DatetimePickerViewColumnType, + value: number, + currentArray: number[], + boundary: number[] +): boolean { + const { type } = props + + switch (type) { + case 'datetime': { + const [year, month, date, hour, minute] = boundary + if (columnType === 'year') { + return isStart ? value > year : value < year + } + if (columnType === 'month' && currentArray[0] === year) { + return isStart ? value > month : value < month + } + if (columnType === 'date' && currentArray[0] === year && currentArray[1] === month) { + return isStart ? value > date : value < date + } + if (columnType === 'hour' && currentArray[0] === year && currentArray[1] === month && currentArray[2] === date) { + return isStart ? value > hour : value < hour + } + if (columnType === 'minute' && currentArray[0] === year && currentArray[1] === month && currentArray[2] === date && currentArray[3] === hour) { + return isStart ? value > minute : value < minute + } + break + } + case 'year-month': { + const [year, month] = boundary + if (columnType === 'year') { + return isStart ? value > year : value < year + } + if (columnType === 'month' && currentArray[0] === year) { + return isStart ? value > month : value < month + } + break + } + case 'year': { + const [year] = boundary + if (columnType === 'year') { + return isStart ? value > year : value < year + } + break + } + case 'date': { + const [year, month, date] = boundary + if (columnType === 'year') { + return isStart ? value > year : value < year + } + if (columnType === 'month' && currentArray[0] === year) { + return isStart ? value > month : value < month + } + if (columnType === 'date' && currentArray[0] === year && currentArray[1] === month) { + return isStart ? value > date : value < date + } + break + } + case 'time': { + const [hour, minute] = boundary + if (columnType === 'hour') { + return isStart ? value > hour : value < hour + } + if (columnType === 'minute' && currentArray[0] === hour) { + return isStart ? value > minute : value < minute + } + break + } + } + return false +} + +/** + * @description 自定义列项筛选规则 */ const customColumnFormatter: DatetimePickerViewColumnFormatter = (picker) => { - if (!picker) { - return [] - } + if (!picker) return [] + const { type } = props const { startSymbol, formatter } = picker - // 校准上下方picker的value值,与内部innerValue对应 const start = picker.correctValue(innerValue.value) const end = picker.correctValue(endInnerValue.value) - /** - * 如果是上方picekr 那么将下方picker的值作为下边界 - * 如果是下方picekr 那么将上方picker的值作为上边界 - */ const currentValue = startSymbol ? picker.getPickerValue(start, type) : picker.getPickerValue(end, type) const boundary = startSymbol ? picker.getPickerValue(end, type) : picker.getPickerValue(start, type) - // 获取当前picekr中的源列数组 const columns = picker.getOriginColumns() - // 此时index是最外层知道当前的索引即可得到当前是哪个时间段 - return columns.map((column, cIndex) => { + return columns.map((column, _) => { return column.values.map((value) => { - const disabled = columnDisabledRules(startSymbol, columns, cIndex, value, currentValue, boundary) + const disabled = handleBoundaryValue(startSymbol, column.type, value, currentValue, boundary) return { label: formatter ? formatter(column.type, padZero(value)) : padZero(value), value, @@ -415,9 +487,6 @@ function close() { onCancel() } -/** - * @description 展示popup,小程序有个bug,在picker-view弹出时设置value,会触发change事件,而且会将picker-view的value多次触发change重置为第一项 - */ function showPopup() { if (props.disabled || props.readonly) return @@ -450,15 +519,34 @@ function tabChange() { * @description datetimePickerView change 事件 */ function onChangeStart({ value }: { value: number | string }) { - innerValue.value = deepClone(value) + if (!datetimePickerView.value) return + if (region.value && !datetimePickerView1.value) return + if (region.value) { - showTabLabel.value = [setTabLabel(), deepClone(showTabLabel.value[1])] - emit('change', { - value: [value, endInnerValue.value] + // 区间选择才需要处理边界值 + const currentArray = datetimePickerView.value.getPickerValue(value, props.type) + const boundaryArray = datetimePickerView.value.getPickerValue(endInnerValue.value, props.type) + const columns = datetimePickerView.value.getOriginColumns() + + // 检查是否有任何列超出边界 + const needsAdjust = columns.some((column, index) => { + return handleBoundaryValue(true, column.type, currentArray[index], currentArray, boundaryArray) + }) + + innerValue.value = deepClone(needsAdjust ? endInnerValue.value : value) + + nextTick(() => { + showTabLabel.value = [setTabLabel(), deepClone(showTabLabel.value[1])] + emit('change', { + value: [innerValue.value, endInnerValue.value] + }) + // 更新两个picker的列 + datetimePickerView.value && datetimePickerView.value.setColumns(datetimePickerView.value.updateColumns()) + datetimePickerView1.value && datetimePickerView1.value.setColumns(datetimePickerView1.value.updateColumns()) }) - datetimePickerView.value && datetimePickerView.value.setColumns(datetimePickerView.value.updateColumns()) - datetimePickerView1.value && datetimePickerView1.value.setColumns(datetimePickerView1.value.updateColumns()) } else { + // 非区间选择直接设置值即可 + innerValue.value = deepClone(value) emit('change', { value: innerValue.value }) @@ -469,13 +557,28 @@ function onChangeStart({ value }: { value: number | string }) { * @description 区域选择 下方 datetimePickerView change 事件 */ function onChangeEnd({ value }: { value: number | string }) { - endInnerValue.value = deepClone(value) - showTabLabel.value = [deepClone(showTabLabel.value[0]), setTabLabel(1)] - emit('change', { - value: [innerValue.value, value] + if (!datetimePickerView.value || !datetimePickerView1.value) return + + const currentArray = datetimePickerView1.value.getPickerValue(value, props.type) + const boundaryArray = datetimePickerView1.value.getPickerValue(innerValue.value, props.type) + const columns = datetimePickerView1.value.getOriginColumns() + + // 检查是否有任何列超出边界 + const needsAdjust = columns.some((column, index) => { + return handleBoundaryValue(false, column.type, currentArray[index], currentArray, boundaryArray) + }) + + endInnerValue.value = deepClone(needsAdjust ? innerValue.value : value) + + nextTick(() => { + showTabLabel.value = [deepClone(showTabLabel.value[0]), setTabLabel(1)] + emit('change', { + value: [innerValue.value, endInnerValue.value] + }) + // 更新两个picker的列 + datetimePickerView.value && datetimePickerView.value.setColumns(datetimePickerView.value.updateColumns()) + datetimePickerView1.value && datetimePickerView1.value.setColumns(datetimePickerView1.value.updateColumns()) }) - datetimePickerView.value && datetimePickerView.value.setColumns(datetimePickerView.value.updateColumns()) - datetimePickerView1.value && datetimePickerView1.value.setColumns(datetimePickerView1.value.updateColumns()) } /** @@ -620,11 +723,6 @@ function defaultDisplayFormat(items: Record[], tabLabel: boolean = // 如果使用了自定义的的formatter,defaultDisplayFormat无效 if (props.formatter) { - /** - * 不建议使用 this.picker.picker.getLabels() 拉取 - * 在初始展示时,需要使用模拟 nextTick 来等待内部 pickerView 渲染后labels才可得到format后的labels - * 但使用模拟nextTick会造成页面延迟展示问题,对用户感知来讲不友好,因此不适用该方法 - */ const typeMaps = { year: ['year'], datetime: ['year', 'month', 'date', 'hour', 'minute'], @@ -653,100 +751,6 @@ function defaultDisplayFormat(items: Record[], tabLabel: boolean = } } -/** - * @description 区域选择time禁用规则,根据传入的位置标志以及日期类型 返回该节点是否禁用 - * @param {Boolean} isStart 时间段类型 true:start | false:end - * @param {Array} column 当前遍历到的列数组 - * @param {Number} cindex 外层column的索引(对应每一个类型) - * @param {Number / String} value 遍历到的当前值 - * @param {Array} currentValue 当前选中的值 this.pickerValue - * @param {Array} boundary 当前变量的限制值,决定禁用的边界值 - * @return {Boolean} disabled - */ -function columnDisabledRules( - isStart: boolean, - columns: { - type: DatetimePickerViewColumnType - values: number[] - }[], - cIndex: number, - value: number, - currentValue: number[], - boundary: number[] -) { - const { type } = props - // 0年 1月 2日 3時 4分 - // startPicker 除最小值外 还需要有一个时间限制, endPicker 时间选择后, startPicker 的 添加一个时间限制boundary min->boundary - // endPicker 除最小值外 还需要有一个时间限制, startPicker 时间选择后, endPicker 的 添加一个时间限制boundary boundary->max - const column = columns[cIndex] - // 根据当前选择年确认 ranges[0][0] minYear ranges[0][1] maxYear 以此类推 - if (type === 'datetime') { - const year = boundary[0] - const month = boundary[1] - const date = boundary[2] - const hour = boundary[3] - const minute = boundary[4] - - if (column.type === 'year') { - return isStart ? value > year : value < year - } - if (column.type === 'month' && currentValue[0] === year) { - return isStart ? value > month : value < month - } - if (column.type === 'date' && currentValue[0] === year && currentValue[1] === month) { - return isStart ? value > date : value < date - } - if (column.type === 'hour' && currentValue[0] === year && currentValue[1] === month && currentValue[2] === date) { - return isStart ? value > hour : value < hour - } - if (column.type === 'minute' && currentValue[0] === year && currentValue[1] === month && currentValue[2] === date && currentValue[3] === hour) { - return isStart ? value > minute : value < minute - } - } else if (type === 'year-month') { - const year = boundary[0] - const month = boundary[1] - - if (column.type === 'year') { - return isStart ? value > year : value < year - } - if (column.type === 'month' && currentValue[0] === year) { - return isStart ? value > month : value < month - } - } else if (type === 'year') { - const year = boundary[0] - - if (column.type === 'year') { - return isStart ? value > year : value < year - } - } else if (type === 'date') { - const year = boundary[0] - const month = boundary[1] - const date = boundary[2] - - if (column.type === 'year') { - return isStart ? value > year : value < year - } - if (column.type === 'month' && currentValue[0] === year) { - return isStart ? value > month : value < month - } - if (column.type === 'date' && currentValue[0] === year && currentValue[1] === month) { - return isStart ? value > date : value < date - } - } else if (type === 'time') { - const hour = boundary[0] - const minute = boundary[1] - - if (column.type === 'hour') { - return isStart ? value > hour : value < hour - } - if (column.type === 'minute' && currentValue[0] === hour) { - return isStart ? value > minute : value < minute - } - } - - return false -} - function setLoading(loading: boolean) { isLoading.value = loading }