✨ 优化日期选择和提示圆角
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
v-for="alert in alerts"
|
||||
:key="alert.id"
|
||||
:class="[
|
||||
'w-full rounded-lg shadow-xl overflow-hidden',
|
||||
'w-full rounded-[30px] shadow-xl overflow-hidden',
|
||||
'bg-gradient-to-r',
|
||||
gradientClasses[alert.type]
|
||||
]"
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div class="grid w-full grid-cols-3 gap-2 sm:w-auto">
|
||||
<select
|
||||
:value="parts.year"
|
||||
class="h-12 min-w-0 rounded-[30px] border px-3 text-sm"
|
||||
:class="fieldClass"
|
||||
:aria-label="`${ariaLabel}年`"
|
||||
@change="updatePart('year', ($event.target as HTMLSelectElement).value)"
|
||||
>
|
||||
<option v-for="year in years" :key="year" :value="year">{{ year }}年</option>
|
||||
</select>
|
||||
<select
|
||||
:value="parts.month"
|
||||
class="h-12 min-w-0 rounded-[30px] border px-3 text-sm"
|
||||
:class="fieldClass"
|
||||
:aria-label="`${ariaLabel}月`"
|
||||
@change="updatePart('month', ($event.target as HTMLSelectElement).value)"
|
||||
>
|
||||
<option v-for="month in months" :key="month" :value="month">
|
||||
{{ month.toString().padStart(2, '0') }}月
|
||||
</option>
|
||||
</select>
|
||||
<select
|
||||
:value="parts.day"
|
||||
class="h-12 min-w-0 rounded-[30px] border px-3 text-sm"
|
||||
:class="fieldClass"
|
||||
:aria-label="`${ariaLabel}日`"
|
||||
@change="updatePart('day', ($event.target as HTMLSelectElement).value)"
|
||||
>
|
||||
<option v-for="day in days" :key="day" :value="day">
|
||||
{{ day.toString().padStart(2, '0') }}日
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue: string
|
||||
fieldClass?: string | string[]
|
||||
ariaLabel?: string
|
||||
minYear?: number
|
||||
maxYear?: number
|
||||
}>(),
|
||||
{
|
||||
fieldClass: '',
|
||||
ariaLabel: '日期',
|
||||
minYear: 1900,
|
||||
maxYear: 2100
|
||||
}
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
change: []
|
||||
}>()
|
||||
|
||||
type DatePart = 'year' | 'month' | 'day'
|
||||
|
||||
const pad = (value: number) => String(value).padStart(2, '0')
|
||||
const clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value))
|
||||
const getDaysInMonth = (year: number, month: number) => new Date(year, month, 0).getDate()
|
||||
|
||||
const years = computed(() =>
|
||||
Array.from({ length: props.maxYear - props.minYear + 1 }, (_, index) => props.minYear + index)
|
||||
)
|
||||
const months = Array.from({ length: 12 }, (_, index) => index + 1)
|
||||
|
||||
const parts = computed(() => {
|
||||
const [rawYear, rawMonth, rawDay] = props.modelValue.split('-').map(Number)
|
||||
const year = clamp(Number.isFinite(rawYear) ? rawYear : new Date().getFullYear(), props.minYear, props.maxYear)
|
||||
const month = clamp(Number.isFinite(rawMonth) ? rawMonth : new Date().getMonth() + 1, 1, 12)
|
||||
const day = clamp(
|
||||
Number.isFinite(rawDay) ? rawDay : new Date().getDate(),
|
||||
1,
|
||||
getDaysInMonth(year, month)
|
||||
)
|
||||
return { year, month, day }
|
||||
})
|
||||
|
||||
const days = computed(() =>
|
||||
Array.from(
|
||||
{ length: getDaysInMonth(parts.value.year, parts.value.month) },
|
||||
(_, index) => index + 1
|
||||
)
|
||||
)
|
||||
|
||||
const updatePart = (part: DatePart, value: string) => {
|
||||
const next = { ...parts.value, [part]: Number(value) }
|
||||
next.day = clamp(next.day, 1, getDaysInMonth(next.year, next.month))
|
||||
emit('update:modelValue', `${next.year}-${pad(next.month)}-${pad(next.day)}`)
|
||||
emit('change')
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user