You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

850 lines
26 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view
:class="`wd-picker ${disabled ? 'is-disabled' : ''} ${size ? 'is-' + size : ''} ${cell.border.value ? 'is-border' : ''} ${
alignRight ? 'is-align-right' : ''
} ${error ? 'is-error' : ''} ${customClass}`"
>
<!--文案-->
<view class="wd-picker__field" @click="showPopup">
<slot v-if="useDefaultSlot"></slot>
<view v-else class="wd-picker__cell">
<view
v-if="label || useLabelSlot"
:class="`wd-picker__label ${customLabelClass} ${isRequired ? 'is-required' : ''}`"
:style="labelWidth ? 'min-width:' + labelWidth + ';max-width:' + labelWidth + ';' : ''"
>
<block v-if="label">{{ label }}</block>
<slot v-else name="label"></slot>
</view>
<view class="wd-picker__body">
<view class="wd-picker__value-wraper">
<view :class="`wd-picker__value ${customValueClass}`">
<view v-if="region">
<text :class="showValue[0] ? '' : 'wd-picker__placeholder'">{{ showValue[0] ? showValue[0] : placeholder }}</text>
<text :class="showValue[1] ? '' : 'wd-picker__placeholder'">{{ showValue[1] ? showValue[1] : placeholder }}</text>
</view>
<view v-else :class="showValue ? '' : 'wd-picker__placeholder'">
{{ showValue ? showValue : placeholder }}
</view>
</view>
<wd-icon v-if="!disabled && !readonly" custom-class="wd-picker__arrow" name="arrow-right" />
</view>
<view v-if="errorMessage" class="wd-picker__error-message">{{ errorMessage }}</view>
</view>
</view>
</view>
<!--弹出层picker-view 在隐藏时修改值会触发多次change事件从而导致所有列选中第一项因此picker在关闭时不隐藏 -->
<wd-popup
v-model="popupShow"
position="bottom"
:hide-when-close="false"
:close-on-click-modal="closeOnClickModal"
:safe-area-inset-bottom="safeAreaInsetBottom"
:z-index="zIndex"
@close="onCancel"
custom-class="wd-picker__popup"
>
<view class="wd-picker__wraper">
<!--toolBar-->
<view class="wd-picker__toolbar" @touchmove="noop">
<!--取消按钮-->
<view class="wd-picker__action wd-picker__action--cancel" @click="onCancel">
{{ cancelButtonText }}
</view>
<!--标题-->
<view v-if="title" class="wd-picker__title">{{ title }}</view>
<!--确定按钮-->
<view :class="`wd-picker__action ${loading || isLoading ? 'is-loading' : ''}`" @click="onConfirm">
{{ confirmButtonText }}
</view>
</view>
<!-- 区域选择tab展示 -->
<view v-if="region" class="wd-picker__region-tabs">
<view :class="`wd-picker__region ${showStart ? 'is-active' : ''} `" @click="tabChange">
<view>开始时间</view>
<view class="wd-picker__region-time">{{ showTabLabel[0] }}</view>
</view>
<view :class="`wd-picker__region ${showStart ? '' : 'is-active'}`" @click="tabChange">
<view>结束时间</view>
<view class="wd-picker__region-time">{{ showTabLabel[1] }}</view>
</view>
</view>
<!--datetimePickerView-->
<view :class="showStart ? 'wd-picker__show' : 'wd-picker__hidden'">
<wd-datetime-picker-view
:custom-class="customViewClass"
ref="datetimePickerView"
:type="type"
v-model="innerValue"
:loading="loading || isLoading"
:loading-color="loadingColor"
:columns-height="columnsHeight"
:value-key="valueKey"
:label-key="labelKey"
:formatter="formatter"
:filter="filter"
:column-formatter="getType(modelValue) === 'array' ? customColumnFormatter : undefined"
:max-hour="maxHour"
:min-hour="minHour"
:max-date="maxDate"
:min-date="minDate"
:max-minute="maxMinute"
:min-minute="minMinute"
:start-symbol="true"
@change="onChangeStart"
@pickstart="onPickStart"
@pickend="onPickEnd"
/>
</view>
<view :class="showStart ? 'wd-picker__hidden' : 'wd-picker__show'">
<wd-datetime-picker-view
:custom-class="customViewClass"
ref="datetimePickerView1"
:type="type"
v-model="endInnerValue"
:loading="loading || isLoading"
:loading-color="loadingColor"
:columns-height="columnsHeight"
:value-key="valueKey"
:label-key="labelKey"
:formatter="formatter"
:filter="filter"
:column-formatter="getType(modelValue) === 'array' ? customColumnFormatter : undefined"
:max-hour="maxHour"
:min-hour="minHour"
:max-date="maxDate"
:min-date="minDate"
:max-minute="maxMinute"
:min-minute="minMinute"
:start-symbol="false"
@change="onChangeEnd"
@pickstart="onPickStart"
@pickend="onPickEnd"
/>
</view>
</view>
</wd-popup>
</view>
</template>
<script lang="ts">
export default {
name: 'wd-datetime-picker',
options: {
virtualHost: true,
addGlobalClass: true,
styleIsolation: 'shared'
}
}
</script>
<script lang="ts" setup>
import { computed, getCurrentInstance, nextTick, onBeforeMount, onMounted, ref, watch } from 'vue'
import { deepClone, getType, isArray, isDef, isEqual, padZero } from '../common/util'
import { useCell } from '../composables/useCell'
import { type DateTimeType, getPickerValue } from '../wd-datetime-picker-view/type'
import { FORM_KEY, FormItemRule } from '../wd-form/types'
import { useParent } from '../composables/useParent'
interface Props {
customClass?: string
customViewClass?: string
customLabelClass?: string
customValueClass?: string
// 选择器左侧文案
label?: string
// 选择器占位符
placeholder?: string
// 禁用
disabled?: boolean
// 只读
readonly?: boolean
loading?: boolean
loadingColor?: string
/* popup */
// 弹出层标题
title?: string
// 取消按钮文案
cancelButtonText?: string
// 确认按钮文案
confirmButtonText?: string
// 是否必填
required?: boolean
size?: string
labelWidth?: string
useDefaultSlot?: boolean
useLabelSlot?: boolean
error?: boolean
alignRight?: boolean
closeOnClickModal?: boolean
safeAreaInsetBottom?: boolean
ellipsis?: boolean
// 选项总高度
columnsHeight?: number
// 选项对象中value对应的 key
valueKey?: string
// 选项对象中,展示的文本对应的 key
labelKey?: string
// 选中项,当 type 为 time 时,类型为字符串,否则为 时间戳
modelValue: string | number | Date | Array<string | number | Date>
// 时间选择器的类型
type?: DateTimeType
// 最小日期 20(x-10)年1月1日
minDate?: number
// 最大日期 20(x+10)年1月1日
maxDate?: number
// 最小小时
minHour?: number
// 最大小时
maxHour?: number
// 最小分钟
minMinute?: number
// 最大分钟
maxMinute?: number
// 自定义过滤选项的函数,返回列的选项数组
// eslint-disable-next-line @typescript-eslint/ban-types
filter?: Function
// 自定义弹出层选项文案的格式化函数,返回一个字符串
// eslint-disable-next-line @typescript-eslint/ban-types
formatter?: Function
// 自定义展示文案的格式化函数,返回一个字符串
// eslint-disable-next-line @typescript-eslint/ban-types
displayFormat?: Function
// 自定义展示文案的格式化函数,返回一个字符串
// eslint-disable-next-line @typescript-eslint/ban-types
beforeConfirm?: Function
// 自定义展示文案的格式化函数,返回一个字符串
// eslint-disable-next-line @typescript-eslint/ban-types
displayFormatTabLabel?: Function
defaultValue?: string | number | Date | Array<string | number | Date>
zIndex?: number
prop?: string
rules?: FormItemRule[]
}
const props = withDefaults(defineProps<Props>(), {
customClass: '',
customViewClass: '',
customLabelClass: '',
customValueClass: '',
// 选择器占位符
placeholder: '请选择',
// 禁用
disabled: false,
// 只读
readonly: false,
loading: false,
loadingColor: '#4D80F0',
/* popup */
// 取消按钮文案
cancelButtonText: '取消',
// 确认按钮文案
confirmButtonText: '完成',
// 是否必填
required: false,
labelWidth: '33%',
useDefaultSlot: false,
useLabelSlot: false,
error: false,
alignRight: false,
closeOnClickModal: true,
safeAreaInsetBottom: true,
ellipsis: false,
// 选项总高度
columnsHeight: 217,
// 选项对象中value对应的 key
valueKey: 'value',
// 选项对象中,展示的文本对应的 key
labelKey: 'label',
// 时间选择器的类型
type: 'datetime',
// 最小日期 20(x-10)年1月1日
minDate: new Date(new Date().getFullYear() - 10, 0, 1).getTime(),
// 最大日期 20(x+10)年1月1日
maxDate: new Date(new Date().getFullYear() + 10, 11, 31).getTime(),
// 最小小时
minHour: 0,
// 最大小时
maxHour: 23,
// 最小分钟
minMinute: 0,
// 最大分钟
maxMinute: 59,
zIndex: 15,
rules: () => []
})
const datetimePickerView = ref()
const datetimePickerView1 = ref()
const showValue = ref<string | Date | Array<string | Date>>([])
const popupShow = ref<boolean>(false)
const showStart = ref<boolean>(true)
const region = ref<boolean>(false)
const showTabLabel = ref<string[]>([])
const innerValue = ref<string>('')
const endInnerValue = ref<string>('')
const isPicking = ref<boolean>(false) // 判断pickview是否还在滑动中
const hasConfirmed = ref<boolean>(false) // 判断用户是否点击了确认按钮
const isLoading = ref<boolean>(false) // 加载
const { proxy } = getCurrentInstance() as any
const cell = useCell()
watch(
() => props.modelValue,
(val, oldVal) => {
if (isEqual(val, oldVal)) return
if (getType(val) === 'array') {
region.value = true
innerValue.value = deepClone(getDefaultInnerValue(true))
endInnerValue.value = deepClone(getDefaultInnerValue(true, true))
} else {
// 每次value更新时都需要刷新整个列表
innerValue.value = deepClone(getDefaultInnerValue())
}
nextTick(() => {
setShowValue(false, false, true)
})
},
{
deep: true,
immediate: true
}
)
watch(
() => props.displayFormat,
(fn) => {
if (fn && getType(fn) !== 'function') {
console.error('The type of displayFormat must be Function')
}
},
{
deep: true,
immediate: true
}
)
watch(
() => props.filter,
(fn) => {
if (fn && getType(fn) !== 'function') {
console.error('The type of filter must be Function')
}
},
{
deep: true,
immediate: true
}
)
watch(
() => props.formatter,
(fn) => {
if (fn && getType(fn) !== 'function') {
console.error('The type of formatter must be Function')
}
},
{
deep: true,
immediate: true
}
)
watch(
() => props.beforeConfirm,
(fn) => {
if (fn && getType(fn) !== 'function') {
console.error('The type of beforeConfirm must be Function')
}
},
{
deep: true,
immediate: true
}
)
watch(
() => props.displayFormatTabLabel,
(fn) => {
if (fn && getType(fn) !== 'function') {
console.error('The type of displayFormatTabLabel must be Function')
}
},
{
deep: true,
immediate: true
}
)
watch(
() => props.defaultValue,
(val) => {
if (getType(val) === 'array' || region.value) {
innerValue.value = deepClone(getDefaultInnerValue(true))
endInnerValue.value = deepClone(getDefaultInnerValue(true, true))
} else {
innerValue.value = deepClone(getDefaultInnerValue())
}
},
{
deep: true,
immediate: true
}
)
const { parent: form } = useParent(FORM_KEY)
// 表单校验错误信息
const errorMessage = computed(() => {
if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
return form.errorMessages[props.prop]
} else {
return ''
}
})
// 是否展示必填
const isRequired = computed(() => {
let formRequired = false
if (form && form.rules) {
const rules = form.rules
for (const key in rules) {
if (Object.prototype.hasOwnProperty.call(rules, key) && key === props.prop && Array.isArray(rules[key])) {
formRequired = rules[key].some((rule: FormItemRule) => rule.required)
}
}
}
return props.required || props.rules.some((rule) => rule.required) || formRequired
})
const emit = defineEmits(['change', 'open', 'toggle', 'cancel', 'confirm', 'update:modelValue'])
/**
* @description 自定义列项筛选规则对每列单项进行禁用校验最终返回传入PickerView的columns数组
* @param {Component} picker datetimePickerView对象
* @return {Array} columns
*/
const customColumnFormatter = (picker) => {
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()
const mapColumns = (columns) => {
// 此时index是最外层知道当前的索引即可得到当前是哪个时间段
return columns.map((column, cIndex) => {
return column.values.map((value, index) => {
const disabled = columnDisabledRules(startSymbol, columns, cIndex, value, currentValue, boundary)
return {
label: formatter ? formatter(column.type, padZero(value)) : padZero(value),
value,
disabled
}
})
})
}
return mapColumns(columns)
}
onBeforeMount(() => {
const { modelValue: value } = props
if (getType(value) === 'array') {
region.value = true
innerValue.value = deepClone(getDefaultInnerValue(true))
endInnerValue.value = deepClone(getDefaultInnerValue(true, true))
} else {
innerValue.value = deepClone(getDefaultInnerValue())
}
})
onMounted(() => {
setShowValue(false, false, true)
})
/**
* @description 根据传入的pickerpicker组件获取当前cell展示值。
*/
function getSelects(picker: 'before' | 'after') {
let value = picker === 'before' ? innerValue.value : endInnerValue.value
let selected: number[] = []
if (value) {
selected = getPickerValue(value, props.type)
}
let selects = selected.map((value) => {
return {
[props.labelKey]: padZero(value),
[props.valueKey]: value
}
})
return selects
}
function noop() {}
function getDefaultInnerValue(isRegion?: boolean, isEnd?: boolean) {
const { modelValue: value, defaultValue } = props
if (isRegion) {
if (isEnd) {
return value[1] || (defaultValue && isArray(defaultValue) ? defaultValue[1] : '')
} else {
return value[0] || (defaultValue && isArray(defaultValue) ? defaultValue[0] : '')
}
} else {
return isDef(value || defaultValue) ? value || defaultValue : ''
}
}
// 对外暴露接口,打开弹框
function open() {
showPopup()
}
// 对外暴露接口,关闭弹框
function close() {
onCancel()
}
/**
* @description 展示popup小程序有个bug在picker-view弹出时设置value会触发change事件而且会将picker-view的value多次触发change重置为第一项
*/
function showPopup() {
if (props.disabled || props.readonly) return
emit('open')
if (region.value) {
popupShow.value = true
showStart.value = true
innerValue.value = deepClone(getDefaultInnerValue(true, false))
endInnerValue.value = deepClone(getDefaultInnerValue(true, true))
} else {
popupShow.value = true
innerValue.value = deepClone(getDefaultInnerValue())
}
setShowValue(true, false, true)
}
/**
* @description 区域选择时tab标签切换时触发
*/
function tabChange() {
showStart.value = !showStart.value
// 列项刷新多级联动挂载到datetimepickerView
const picker = showStart.value ? datetimePickerView.value : datetimePickerView1.value
picker.setColumns(picker.updateColumns())
emit('toggle', showStart.value ? innerValue.value : endInnerValue.value)
}
/**
* @description datetimePickerView change 事件
*/
function onChangeStart({ value }) {
innerValue.value = deepClone(value)
if (region.value) {
showTabLabel.value = [setTabLabel(), deepClone(showTabLabel.value[1])]
emit('change', {
value: [value, endInnerValue.value]
})
datetimePickerView.value && datetimePickerView.value.setColumns(datetimePickerView.value.updateColumns())
datetimePickerView1.value && datetimePickerView1.value.setColumns(datetimePickerView1.value.updateColumns())
} else {
// emit('update:modelValue', innerValue.value)
emit('change', {
value: innerValue.value
})
}
}
/**
* @description 区域选择 下方 datetimePickerView change 事件
*/
function onChangeEnd({ value }) {
endInnerValue.value = deepClone(value)
showTabLabel.value = [deepClone(showTabLabel.value[0]), setTabLabel(1)]
// emit('update:modelValue', [innerValue.value, value])
emit('change', {
value: [innerValue.value, value]
})
datetimePickerView.value && datetimePickerView.value.setColumns(datetimePickerView.value.updateColumns())
datetimePickerView1.value && datetimePickerView1.value.setColumns(datetimePickerView1.value.updateColumns())
}
/**
* @description 点击取消按钮触发。关闭popup触发cancel事件。
*/
function onCancel() {
popupShow.value = false
setTimeout(() => {
if (region.value) {
innerValue.value = deepClone(getDefaultInnerValue(true))
endInnerValue.value = deepClone(getDefaultInnerValue(true, true))
} else {
innerValue.value = deepClone(getDefaultInnerValue())
}
}, 200)
emit('cancel')
}
/** picker触发confirm事件同步触发confirm事件 */
function onConfirm() {
if (props.loading || isLoading.value) return
// 如果当前还在滑动且未停止下来则锁住先不确认等滑完再自动确认避免pickview值未更新
if (isPicking.value) {
hasConfirmed.value = true
return
}
const { beforeConfirm } = props
if (beforeConfirm) {
beforeConfirm(
region.value ? [innerValue.value, endInnerValue.value] : innerValue.value,
(isPass: boolean) => {
isPass && handleConfirm()
},
proxy.$.exposed
)
} else {
handleConfirm()
}
}
function onPickStart() {
isPicking.value = true
}
function onPickEnd() {
isPicking.value = false
// 延迟一会,因为组件层级嵌套过多,日期的计算时间也较长
setTimeout(() => {
if (hasConfirmed.value) {
hasConfirmed.value = false
onConfirm()
}
}, 50)
}
function handleConfirm() {
if (props.loading || isLoading.value || props.disabled) {
popupShow.value = false
return
}
const value = region.value ? [innerValue.value, endInnerValue.value] : innerValue.value
popupShow.value = false
emit('update:modelValue', value)
emit('confirm', {
value
})
setShowValue(false, true)
}
/**
* @description 设置区域选择 tab 标签展示值
* @param {Number} index 索引标志位,有三个有效值; 0(默认):上方picker索引; 1:下方picker索引;
* @return {String} showTabLabel
*/
function setTabLabel(index: number = 0) {
if (region.value) {
let items = []
if (index === 0) {
items =
(datetimePickerView.value && datetimePickerView.value.getSelects && datetimePickerView.value.getSelects()) ||
(innerValue.value && getSelects('before'))
} else {
items =
(datetimePickerView1.value && datetimePickerView1.value.getSelects && datetimePickerView1.value.getSelects()) ||
(endInnerValue.value && getSelects('after'))
}
return defaultDisplayFormat(items, true)
}
}
/**
* @description 设置展示值
* @param {Boolean} tab 是否修改tab展示值尽在区域选择情况下生效
* @param {Boolean} isConfirm 是否提交当前修改
*/
function setShowValue(tab: boolean = false, isConfirm: boolean = false, beforeMount: boolean = false) {
if (region.value) {
const items = beforeMount
? (innerValue.value && getSelects('before')) || []
: (datetimePickerView.value && datetimePickerView.value.getSelects && datetimePickerView.value.getSelects()) || []
const endItems = beforeMount
? (endInnerValue.value && getSelects('after')) || []
: (datetimePickerView1.value && datetimePickerView1.value.getSelects && datetimePickerView1.value.getSelects()) || []
showValue.value = tab
? showValue.value
: [props.modelValue[0] || isConfirm ? defaultDisplayFormat(items) : '', props.modelValue[1] || isConfirm ? defaultDisplayFormat(endItems) : '']
showTabLabel.value = [defaultDisplayFormat(items, true), defaultDisplayFormat(endItems, true)]
} else {
const items = beforeMount
? (innerValue.value && getSelects('before')) || []
: (datetimePickerView.value && datetimePickerView.value.getSelects && datetimePickerView.value.getSelects()) || []
showValue.value = deepClone(props.modelValue || isConfirm ? defaultDisplayFormat(items) : '')
}
}
/**
* @description 设置展示值
* @param {Object} items 获取到的选中项 包含 { value, label }
* @param {Boolean} tabLabel 当前返回的是否是展示tab上的标签
* @return {String} showValue / showTabLabel
*/
function defaultDisplayFormat(items, tabLabel = false) {
if (items.length === 0) return ''
if (tabLabel && props.displayFormatTabLabel) {
return props.displayFormatTabLabel(items)
}
if (props.displayFormat) {
return props.displayFormat(items)
}
// 如果使用了自定义的的formatterdefaultDisplayFormat无效
if (props.formatter) {
/**
* 不建议使用 this.picker.picker.getLabels() 拉取
* 在初始展示时,需要使用模拟 nextTick 来等待内部 pickerView 渲染后labels才可得到format后的labels
* 但使用模拟nextTick会造成页面延迟展示问题对用户感知来讲不友好因此不适用该方法
*/
const map = (items) => {
const typeMaps = {
datetime: ['year', 'month', 'date', 'hour', 'minute'],
date: ['year', 'month', 'date'],
time: ['hour', 'minute'],
'year-month': ['year', 'month']
}
return items.map((item, index) => {
return props.formatter!(typeMaps[props.type][index], item.value)
})
}
return map(items).join('')
}
switch (props.type) {
case 'date':
return `${items[0].label}-${items[1].label}-${items[2].label}`
case 'year-month':
return `${items[0].label}-${items[1].label}`
case 'time':
return `${items[0].label}:${items[1].label}`
case 'datetime':
return `${items[0].label}-${items[1].label}-${items[2].label} ${items[3].label}:${items[4].label}`
}
}
/**
* @description 区域选择time禁用规则根据传入的位置标志以及日期类型 返回该节点是否禁用
* @param {String} isStart 时间段类型 truestart | falseend
* @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, columns, cIndex, value, currentValue, boundary) {
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 === '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) {
isLoading.value = loading
}
defineExpose({
open,
close,
setLoading
})
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>