123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- import { ref, computed } from 'vue'
- import { Field as VanField, Popup as VanPopup, Picker as VanPicker, DatetimePicker as VanDatetimePicker } from 'vant'
- import { formInputProps } from '../../form-input-props'
- import { useFormInput } from '../../../hooks/form-input'
- import dayjs from 'dayjs'
- import advancedFormat from 'dayjs/plugin/advancedFormat'
- import weekYear from 'dayjs/plugin/weekYear'
- import weekOfYear from 'dayjs/plugin/weekOfYear'
- dayjs.extend(advancedFormat)
- dayjs.extend(weekYear)
- dayjs.extend(weekOfYear)
- export default {
- props: formInputProps,
- setup (props, context) {
- const { width, clearable, placeholder, emitModelValue } = useFormInput(props, context)
- const show = ref(false)
- const openPicker = () => {
- show.value = true
- }
- const formatter = computed(() => {
- if (props.config?.formatter) {
- return props.config?.formatter
- } else {
- const typeToFormatter = {
- year: 'YYYY',
- month: 'YYYY-MM',
- week: 'YYYY 第 ww 周',
- date: 'YYYY-MM-DD',
- datetime: 'YYYY-MM-DD HH:mm:ss'
- }
- return typeToFormatter[type.value] ?? typeToFormatter.date
- }
- })
- const type = computed(() => {
- const viewType = props.config?.viewType ?? 'date'
- return viewType.includes('range') ? 'date' : viewType
- })
- // vant对dataType的特殊处理
- const vantType = computed(() => {
- if (type.value === 'month') return 'year-month'
- return type.value
- })
- const isTimestamp = computed(() => {
- return props.config?.isTimestamp ?? false
- })
- // 展示的时间转换
- const transValue = computed(() => {
- if (!props.modelValue) return null
- if (isTimestamp.value) {
- return dayjs(props.modelValue).format(formatter.value)
- }
- if (type.value === 'dates') {
- return props.modelValue.split(',')
- }
- return dayjs(props.modelValue).format(formatter.value)
- })
- const pickerValue = computed(() => {
- return props.modelValue ? new Date(props.modelValue) : new Date()
- })
- // 时间选择范围确定,最小时间和最大时间
- const currentYear = new Date().getFullYear()
- const minDate = computed(() => {
- return props.config?.minDate ?? new Date(currentYear - 10, 0, 1)
- })
- const maxDate = computed(() => {
- return props.config?.maxDate ?? new Date(currentYear + 10, 11, 31)
- })
- // 确定按钮
- const confirm = (value) => {
- show.value = false
- emitModelValue(typeToValue(value))
- }
- // 取消按钮
- const cancel = () => {
- show.value = false
- }
- // 不同事件类型传值不同,做转换
- const typeToValue = (val) => {
- if (!val) return ''
- if (isTimestamp.value) {
- return new Date(val).getTime()
- } else if (type.value === 'datetime') {
- return dayjs(val).format('YYYY-MM-DD HH:mm:ss')
- }
- return dayjs(val).format(formatter.value)
- }
- // 年/月单独实现
- const times = (n, iteratee) => {
- if (n < 0) return []
- const result = new Array(n)
- let index = -1
- while (++index < n) {
- result[index] = iteratee(index)
- }
- return result
- }
- // 月份前置0
- const padZero = (num, targetLength = 2) => {
- let str = num + ''
- while (str.length < targetLength) {
- str = '0' + str
- }
- return str
- }
- // 年月的选项列表
- const columns = computed(() => {
- const ranges = [
- { type: 'year', range: [dayjs(minDate.value).format('YYYY'), dayjs(maxDate.value).format('YYYY')] }
- // { type: 'month', range: [dayjs(minDate.value).format('MM'), dayjs(maxDate.value).format('MM')] }
- ]
- const { range = null } = ranges.find(v => v.type === type.value)
- if (range) return times(range[1] - range[0] + 1, (index) => padZero(parseInt(range[0]) + index))
- return []
- })
- // 年月的默认选中值设置
- const defaultIndex = computed(() => {
- if (type.value === 'year') {
- return columns.value.findIndex(v => v === new Date().getFullYear().toString())
- }
- if (type.value === 'month') {
- return columns.value.findIndex(v => v === new Date().getMonth().toString())
- }
- return 0
- })
- // 头部标题配置
- const titleMap = {
- year: '选择年',
- month: '选择年月',
- date: '选择年月日',
- datetime: '选择日期时间'
- }
- // 弹窗头部标题
- const title = computed(() => {
- return titleMap[type.value] ?? titleMap.datetime
- })
- return () =>
- <div style={{ width: width.value }}>
- <VanField modelValue={transValue.value}
- placeholder={placeholder.value}
- clearable={clearable.value}
- onclick={openPicker}
- readonly
- is-link />
- <VanPopup show={show.value} position="bottom" style="height: 40%">
- {['year'].includes(type.value)
- ? <VanPicker modelValue={pickerValue.value}
- columns={columns.value}
- default-index={defaultIndex.value}
- title={title.value}
- onConfirm={confirm}
- onCancel={cancel}/>
- : <VanDatetimePicker modelValue={pickerValue.value}
- type={vantType.value}
- title={title.value}
- minDate={new Date(minDate.value)}
- maxDate={new Date(maxDate.value)}
- onConfirm={confirm}
- onCancel={cancel} />}
- </VanPopup>
- </div>
- }
- }
|