更新:登录功能
This commit is contained in:
@@ -0,0 +1,389 @@
|
||||
<template>
|
||||
<view>
|
||||
<wd-toast selector="wd-month" />
|
||||
<view class="month">
|
||||
<view class="wd-month">
|
||||
<view class="wd-month__title" v-if="showTitle">{{ monthTitle(date) }}</view>
|
||||
<view class="wd-month__days">
|
||||
<view
|
||||
v-for="(item, index) in days"
|
||||
:key="index"
|
||||
:class="`wd-month__day ${item.disabled ? 'is-disabled' : ''} ${item.isLastRow ? 'is-last-row' : ''} ${
|
||||
item.type ? dayTypeClass(item.type) : ''
|
||||
}`"
|
||||
:style="index === 0 ? firstDayStyle : ''"
|
||||
@click="handleDateClick(index)"
|
||||
>
|
||||
<view class="wd-month__day-container">
|
||||
<view class="wd-month__day-top">{{ item.topInfo }}</view>
|
||||
<view class="wd-month__day-text">
|
||||
{{ item.text }}
|
||||
</view>
|
||||
<view class="wd-month__day-bottom">{{ item.bottomInfo }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
styleIsolation: 'shared'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import wdToast from '../../wd-toast/wd-toast.vue'
|
||||
import { computed, ref, watch, type CSSProperties } from 'vue'
|
||||
import {
|
||||
compareDate,
|
||||
formatMonthTitle,
|
||||
getDateByDefaultTime,
|
||||
getDayByOffset,
|
||||
getDayOffset,
|
||||
getItemClass,
|
||||
getMonthEndDay,
|
||||
getNextDay,
|
||||
getPrevDay,
|
||||
getWeekRange
|
||||
} from '../utils'
|
||||
import { useToast } from '../../wd-toast'
|
||||
import { deepClone, isArray, isFunction, objToStyle } from '../../common/util'
|
||||
import { useTranslate } from '../../composables/useTranslate'
|
||||
import type { CalendarDayItem, CalendarDayType } from '../types'
|
||||
import { monthProps } from './types'
|
||||
|
||||
const props = defineProps(monthProps)
|
||||
const emit = defineEmits(['change'])
|
||||
|
||||
const { translate } = useTranslate('calendar-view')
|
||||
|
||||
const days = ref<Array<CalendarDayItem>>([])
|
||||
|
||||
const toast = useToast('wd-month')
|
||||
|
||||
const offset = computed(() => {
|
||||
const firstDayOfWeek = props.firstDayOfWeek >= 7 ? props.firstDayOfWeek % 7 : props.firstDayOfWeek
|
||||
const offset = (7 + new Date(props.date).getDay() - firstDayOfWeek) % 7
|
||||
return offset
|
||||
})
|
||||
|
||||
const dayTypeClass = computed(() => {
|
||||
return (monthType: CalendarDayType) => {
|
||||
return getItemClass(monthType, props.value, props.type)
|
||||
}
|
||||
})
|
||||
|
||||
const monthTitle = computed(() => {
|
||||
return (date: number) => {
|
||||
return formatMonthTitle(date)
|
||||
}
|
||||
})
|
||||
|
||||
const firstDayStyle = computed(() => {
|
||||
const dayStyle: CSSProperties = {}
|
||||
dayStyle.marginLeft = `${(100 / 7) * offset.value}%`
|
||||
return objToStyle(dayStyle)
|
||||
})
|
||||
|
||||
const isLastRow = (date: number) => {
|
||||
const currentDate = new Date(date)
|
||||
const currentDay = currentDate.getDate()
|
||||
const daysInMonth = getMonthEndDay(currentDate.getFullYear(), currentDate.getMonth() + 1)
|
||||
const totalDaysShown = offset.value + daysInMonth
|
||||
const totalRows = Math.ceil(totalDaysShown / 7)
|
||||
return Math.ceil((offset.value + currentDay) / 7) === totalRows
|
||||
}
|
||||
watch(
|
||||
[() => props.type, () => props.date, () => props.value, () => props.minDate, () => props.maxDate, () => props.formatter],
|
||||
() => {
|
||||
setDays()
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
function setDays() {
|
||||
const dayList: Array<CalendarDayItem> = []
|
||||
const date = new Date(props.date)
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth()
|
||||
const totalDay = getMonthEndDay(year, month + 1)
|
||||
let value = props.value
|
||||
if ((props.type === 'week' || props.type === 'weekrange') && value) {
|
||||
value = getWeekValue()
|
||||
}
|
||||
|
||||
for (let day = 1; day <= totalDay; day++) {
|
||||
const date = new Date(year, month, day).getTime()
|
||||
let type: CalendarDayType = getDayType(date, value as number | number[] | null)
|
||||
if (!type && compareDate(date, Date.now()) === 0) {
|
||||
type = 'current'
|
||||
}
|
||||
const dayObj = getFormatterDate(date, day, type)
|
||||
dayList.push(dayObj)
|
||||
}
|
||||
days.value = dayList
|
||||
}
|
||||
function getDayType(date: number, value: number | number[] | null): CalendarDayType {
|
||||
switch (props.type) {
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
return getDateType(date)
|
||||
case 'dates':
|
||||
return getDatesType(date)
|
||||
case 'daterange':
|
||||
case 'datetimerange':
|
||||
return getDatetimeType(date, value)
|
||||
case 'week':
|
||||
return getWeektimeType(date, value)
|
||||
case 'weekrange':
|
||||
return getWeektimeType(date, value)
|
||||
default:
|
||||
return getDateType(date)
|
||||
}
|
||||
}
|
||||
function getDateType(date: number): CalendarDayType {
|
||||
if (props.value && compareDate(date, props.value as number) === 0) {
|
||||
return 'selected'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function getDatesType(date: number): CalendarDayType {
|
||||
const { value } = props
|
||||
let type: CalendarDayType = ''
|
||||
|
||||
if (!isArray(value)) return type
|
||||
const isSelected = (day: number) => {
|
||||
return value.some((item) => compareDate(day, item) === 0)
|
||||
}
|
||||
|
||||
if (isSelected(date)) {
|
||||
const prevDay = getPrevDay(date)
|
||||
const nextDay = getNextDay(date)
|
||||
const prevSelected = isSelected(prevDay)
|
||||
const nextSelected = isSelected(nextDay)
|
||||
if (prevSelected && nextSelected) {
|
||||
type = 'multiple-middle'
|
||||
} else if (prevSelected) {
|
||||
type = 'end'
|
||||
} else if (nextSelected) {
|
||||
type = 'start'
|
||||
} else {
|
||||
type = 'multiple-selected'
|
||||
}
|
||||
}
|
||||
|
||||
return type
|
||||
}
|
||||
function getDatetimeType(date: number, value: number | number[] | null) {
|
||||
const [startDate, endDate] = isArray(value) ? value : []
|
||||
|
||||
if (startDate && compareDate(date, startDate) === 0) {
|
||||
if (props.allowSameDay && endDate && compareDate(startDate, endDate) === 0) {
|
||||
return 'same'
|
||||
}
|
||||
return 'start'
|
||||
} else if (endDate && compareDate(date, endDate) === 0) {
|
||||
return 'end'
|
||||
} else if (startDate && endDate && compareDate(date, startDate) === 1 && compareDate(date, endDate) === -1) {
|
||||
return 'middle'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
function getWeektimeType(date: number, value: number | number[] | null) {
|
||||
const [startDate, endDate] = isArray(value) ? value : []
|
||||
|
||||
if (startDate && compareDate(date, startDate) === 0) {
|
||||
return 'start'
|
||||
} else if (endDate && compareDate(date, endDate) === 0) {
|
||||
return 'end'
|
||||
} else if (startDate && endDate && compareDate(date, startDate) === 1 && compareDate(date, endDate) === -1) {
|
||||
return 'middle'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
function getWeekValue() {
|
||||
if (props.type === 'week') {
|
||||
return getWeekRange(props.value as number, props.firstDayOfWeek)
|
||||
} else {
|
||||
const [startDate, endDate] = (props.value as any) || []
|
||||
|
||||
if (startDate) {
|
||||
const firstWeekRange = getWeekRange(startDate, props.firstDayOfWeek)
|
||||
|
||||
if (endDate) {
|
||||
const endWeekRange = getWeekRange(endDate, props.firstDayOfWeek)
|
||||
|
||||
return [firstWeekRange[0], endWeekRange[1]]
|
||||
} else {
|
||||
return firstWeekRange
|
||||
}
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
}
|
||||
function handleDateClick(index: number) {
|
||||
const date = days.value[index]
|
||||
switch (props.type) {
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
handleDateChange(date)
|
||||
break
|
||||
case 'dates':
|
||||
handleDatesChange(date)
|
||||
break
|
||||
case 'daterange':
|
||||
case 'datetimerange':
|
||||
handleDateRangeChange(date)
|
||||
break
|
||||
case 'week':
|
||||
handleWeekChange(date)
|
||||
break
|
||||
case 'weekrange':
|
||||
handleWeekRangeChange(date)
|
||||
break
|
||||
default:
|
||||
handleDateChange(date)
|
||||
}
|
||||
}
|
||||
function getDate(date: number, isEnd: boolean = false) {
|
||||
date = props.defaultTime && props.defaultTime.length > 0 ? getDateByDefaultTime(date, isEnd ? props.defaultTime[1] : props.defaultTime[0]) : date
|
||||
|
||||
if (date < props.minDate) return props.minDate
|
||||
|
||||
if (date > props.maxDate) return props.maxDate
|
||||
|
||||
return date
|
||||
}
|
||||
|
||||
function handleDateChange(date: CalendarDayItem) {
|
||||
if (date.disabled) return
|
||||
|
||||
if (date.type !== 'selected') {
|
||||
emit('change', {
|
||||
value: getDate(date.date),
|
||||
type: 'start'
|
||||
})
|
||||
}
|
||||
}
|
||||
function handleDatesChange(date: CalendarDayItem) {
|
||||
if (date.disabled) return
|
||||
const currentValue = deepClone(isArray(props.value) ? props.value : [])
|
||||
const dateIndex = currentValue.findIndex((item) => item && compareDate(item, date.date) === 0)
|
||||
const value = dateIndex === -1 ? [...currentValue, getDate(date.date)] : currentValue.filter((_, index) => index !== dateIndex)
|
||||
emit('change', { value })
|
||||
}
|
||||
|
||||
function handleDateRangeChange(date: CalendarDayItem) {
|
||||
if (date.disabled) return
|
||||
|
||||
let value: (number | null)[] = []
|
||||
let type: CalendarDayType = ''
|
||||
const [startDate, endDate] = deepClone(isArray(props.value) ? props.value : [])
|
||||
const compare = compareDate(date.date, startDate)
|
||||
|
||||
// 禁止选择同个日期
|
||||
if (!props.allowSameDay && compare === 0 && (props.type === 'daterange' || props.type === 'datetimerange') && !endDate) {
|
||||
return
|
||||
}
|
||||
|
||||
if (startDate && !endDate && compare > -1) {
|
||||
// 不能选择超过最大范围的日期
|
||||
if (props.maxRange && getDayOffset(date.date, startDate) > props.maxRange) {
|
||||
const maxEndDate = getDayByOffset(startDate, props.maxRange - 1)
|
||||
value = [startDate, getDate(maxEndDate, true)]
|
||||
toast.show({
|
||||
msg: props.rangePrompt || translate('rangePrompt', props.maxRange)
|
||||
})
|
||||
} else {
|
||||
value = [startDate, getDate(date.date, true)]
|
||||
}
|
||||
} else if (props.type === 'datetimerange' && startDate && endDate) {
|
||||
// 时间范围类型,且有开始时间和结束时间,需要支持重新点击开始日期和结束日期可以重新修改时间
|
||||
if (compare === 0) {
|
||||
type = 'start'
|
||||
value = props.value as number[]
|
||||
} else if (compareDate(date.date, endDate) === 0) {
|
||||
type = 'end'
|
||||
value = props.value as number[]
|
||||
} else {
|
||||
value = [getDate(date.date), null]
|
||||
}
|
||||
} else {
|
||||
value = [getDate(date.date), null]
|
||||
}
|
||||
|
||||
emit('change', {
|
||||
value,
|
||||
type: type || (value[1] ? 'end' : 'start')
|
||||
})
|
||||
}
|
||||
function handleWeekChange(date: CalendarDayItem) {
|
||||
const [weekStart] = getWeekRange(date.date, props.firstDayOfWeek)
|
||||
|
||||
// 周的第一天如果是禁用状态,则不可选中
|
||||
if (getFormatterDate(weekStart, new Date(weekStart).getDate()).disabled) return
|
||||
|
||||
emit('change', {
|
||||
value: getDate(weekStart) + 24 * 60 * 60 * 1000
|
||||
})
|
||||
}
|
||||
function handleWeekRangeChange(date: CalendarDayItem) {
|
||||
const [weekStartDate] = getWeekRange(date.date, props.firstDayOfWeek)
|
||||
|
||||
// 周的第一天如果是禁用状态,则不可选中
|
||||
if (getFormatterDate(weekStartDate, new Date(weekStartDate).getDate()).disabled) return
|
||||
|
||||
let value: (number | null)[] = []
|
||||
const [startDate, endDate] = deepClone(isArray(props.value) ? props.value : [])
|
||||
const [startWeekStartDate] = startDate ? getWeekRange(startDate, props.firstDayOfWeek) : []
|
||||
const compare = compareDate(weekStartDate, startWeekStartDate)
|
||||
|
||||
if (startDate && !endDate && compare > -1) {
|
||||
if (!props.allowSameDay && compare === 0) return
|
||||
|
||||
value = [getDate(startWeekStartDate) + 24 * 60 * 60 * 1000, getDate(weekStartDate) + 24 * 60 * 60 * 1000]
|
||||
} else {
|
||||
value = [getDate(weekStartDate) + 24 * 60 * 60 * 1000, null]
|
||||
}
|
||||
|
||||
emit('change', {
|
||||
value
|
||||
})
|
||||
}
|
||||
function getFormatterDate(date: number, day: string | number, type?: CalendarDayType) {
|
||||
let dayObj: CalendarDayItem = {
|
||||
date: date,
|
||||
text: day,
|
||||
topInfo: '',
|
||||
bottomInfo: '',
|
||||
type,
|
||||
disabled: compareDate(date, props.minDate) === -1 || compareDate(date, props.maxDate) === 1,
|
||||
isLastRow: isLastRow(date)
|
||||
}
|
||||
if (props.formatter) {
|
||||
if (isFunction(props.formatter)) {
|
||||
dayObj = props.formatter(dayObj)
|
||||
} else {
|
||||
console.error('[wot-design] error(wd-calendar-view): the formatter prop of wd-calendar-view should be a function')
|
||||
}
|
||||
}
|
||||
return dayObj
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user