统一预订事项日期选择控件

This commit is contained in:
andy committed 2026-07-22 09:39:31 +07:00
1 parent fb980c6814
commit 434afeb7c5
8 files changed
+315 -271

No files matched your search

@@ -0,0 +1,124 @@
<template>
<DatePicker
v-model="dateModel"
:input-id="inputId"
class="localized-date-picker"
date-format="yy-mm-dd"
:placeholder="placeholder"
:input-class="inputClass"
:pt="datePickerPt"
:invalid="invalid"
:disabled="disabled"
:required="required"
show-icon
icon-display="input"
append-to="body"
:panel-class="panelClass"
/>
</template>
<script setup lang="ts">
import DatePicker from 'primevue/datepicker'
import { usePrimeVue } from 'primevue/config'
import { computed, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import {
formatDatePickerValue,
normalizeDatePickerLocale,
parseDatePickerValue,
primeVueDatePickerLocales,
} from '@/utils/localizedDatePicker'
const props = withDefaults(defineProps<{
modelValue: string
inputId: string
name?: string
testId: string
panelTestId?: string
placeholder?: string
inputClass?: string | Record<string, boolean>
invalid?: boolean
describedBy?: string
disabled?: boolean
required?: boolean
panelClass?: string
}>(), {
name: undefined,
panelTestId: undefined,
placeholder: '',
inputClass: undefined,
invalid: false,
describedBy: undefined,
disabled: false,
required: false,
panelClass: 'localized-date-picker-panel',
})
const emit = defineEmits<{
'update:modelValue': [value: string]
}>()
const { locale } = useI18n()
const primeVue = usePrimeVue()
const dateModel = computed<Date | null>({
get: () => parseDatePickerValue(props.modelValue),
set: (value) => {
emit('update:modelValue', formatDatePickerValue(value))
},
})
const datePickerPt = computed(() => ({
pcInputText: {
root: {
name: props.name,
'data-testid': props.testId,
lang: locale.value,
'aria-invalid': props.invalid ? 'true' : undefined,
'aria-describedby': props.describedBy,
},
},
panel: {
lang: locale.value,
'data-testid': props.panelTestId ?? `${props.testId}-panel`,
},
}))
watch(
locale,
(nextLocale) => {
const supportedLocale = normalizeDatePickerLocale(nextLocale)
primeVue.config.locale = {
...(primeVue.config.locale ?? primeVueDatePickerLocales['en-US']),
...primeVueDatePickerLocales[supportedLocale],
}
},
{ immediate: true },
)
</script>
<style scoped>
.localized-date-picker {
display: block;
width: 100%;
}
.localized-date-picker :deep(.p-inputtext) {
width: 100%;
padding-right: 40px;
}
.localized-date-picker :deep(.p-datepicker-input-icon-container) {
right: 12px;
color: var(--th-color-navy-950);
}
</style>
<style>
.localized-date-picker-panel {
z-index: 1200;
color: var(--th-color-navy-950);
font-family: inherit;
}
</style>
@@ -31,15 +31,16 @@
</option>
</select>
<input
<LocalizedDatePicker
v-else-if="isEditable(field) && isDateField(field)"
class="v4-field__control"
type="date"
:model-value="dateFieldValue(field)"
:input-id="dateFieldInputId(field)"
:name="fieldKey(field)"
:aria-invalid="fieldError(field) ? 'true' : 'false'"
:value="fieldValue(field)"
@input="updateField(field, $event)"
>
:test-id="fieldKey(field)"
:placeholder="t('taskV4.field.datePlaceholder')"
:invalid="Boolean(fieldError(field))"
@update:model-value="updateFieldValue(field, $event)"
/>
<input
v-else-if="isEditable(field) && isCheckboxField(field)"
@@ -120,6 +121,7 @@
import { computed, reactive, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import LocalizedDatePicker from '@/components/common/LocalizedDatePicker.vue'
import {
fetchReservationV4AccountLookups,
fetchReservationV4RateCodeLookups,
@@ -225,6 +227,10 @@ function fieldKey(field: ReservationV4TaskCardFieldResult): string {
return reservationV4FieldKey(field)
}
function dateFieldInputId(field: ReservationV4TaskCardFieldResult): string {
return `v4-date-${fieldKey(field).replace(/[^a-zA-Z0-9_-]/g, '-')}`
}
function isEditable(field: ReservationV4TaskCardFieldResult): boolean {
const key = reservationV4FieldKey(field)
return !props.readOnly &&
@@ -296,6 +302,11 @@ function fieldValue(field: ReservationV4TaskCardFieldResult): string | number {
return stringifyV4Value(value)
}
function dateFieldValue(field: ReservationV4TaskCardFieldResult): string {
const value = readV4FieldValue(field, props.modelValue)
return typeof value === 'string' ? value : stringifyV4Value(value)
}
function staticFieldValue(field: ReservationV4TaskCardFieldResult): string {
const value = fieldValue(field)
const matchedOption = fieldOptions(field).find((option) => option.value === value)
@@ -309,10 +320,14 @@ function checkboxValue(field: ReservationV4TaskCardFieldResult): boolean {
function updateField(field: ReservationV4TaskCardFieldResult, event: Event): void {
const target = event.target as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
updateFieldValue(field, target.value)
}
function updateFieldValue(field: ReservationV4TaskCardFieldResult, value: string): void {
delete invalidLookupValues[reservationV4FieldKey(field)]
emit('update:modelValue', {
...props.modelValue,
[reservationV4FieldKey(field)]: target.value,
[reservationV4FieldKey(field)]: value,
})
}