DateTimePicker.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <template>
  2. <v-row>
  3. <v-col cols="12" md="6">
  4. <v-text-field
  5. :model-value="
  6. dateModel
  7. ? _useDate.format(dateModel, 'fullDateWithWeekday')
  8. : undefined
  9. "
  10. :label="$t('choose_day')"
  11. prepend-icon="fas fa-calendar"
  12. :rules="rules"
  13. :variant="variant"
  14. :error="error || !!fieldViolations"
  15. :error-messages="
  16. errorMessage || (fieldViolations ? $t(fieldViolations) : '')
  17. "
  18. readonly
  19. >
  20. <v-menu
  21. v-model="showMenuDate"
  22. :close-on-content-click="false"
  23. activator="parent"
  24. min-width="0"
  25. >
  26. <v-date-picker
  27. :model-value="dateModel"
  28. @update:model-value="onUpdateDate($event)"
  29. />
  30. </v-menu>
  31. </v-text-field>
  32. </v-col>
  33. <v-col cols="12" md="6">
  34. <v-text-field
  35. :model-value="time"
  36. :variant="variant"
  37. :label="$t('choose_hour')"
  38. prepend-icon="fas fa-clock"
  39. :rules="rules"
  40. :error="error || !!fieldViolations"
  41. :error-messages="
  42. errorMessage || (fieldViolations ? $t(fieldViolations) : '')
  43. "
  44. readonly
  45. >
  46. <v-menu
  47. v-model="showMenuTime"
  48. :close-on-content-click="false"
  49. activator="parent"
  50. min-width="0"
  51. >
  52. <v-time-picker
  53. :model-value="time"
  54. format="24hr"
  55. scrollable
  56. @update:model-value="onUpdateTime($event)"
  57. />
  58. </v-menu>
  59. </v-text-field>
  60. </v-col>
  61. </v-row>
  62. </template>
  63. <script setup lang="ts">
  64. import type { PropType, Ref } from 'vue'
  65. import { ref } from 'vue'
  66. import { useFieldViolation } from '~/composables/form/useFieldViolation'
  67. import { useDate } from 'vuetify'
  68. import DateUtils from '~/services/utils/dateUtils'
  69. const props = defineProps({
  70. /**
  71. * v-model
  72. */
  73. modelValue: {
  74. type: String as PropType<Date | string | null>,
  75. required: false,
  76. default: null,
  77. },
  78. /**
  79. * Nom de la propriété d'une entité lorsque l'input concerne cette propriété
  80. * - Utilisé par la validation
  81. * - Laisser null si le champ ne s'applique pas à une entité
  82. */
  83. field: {
  84. type: String,
  85. required: false,
  86. default: null,
  87. },
  88. /**
  89. * Label du champ
  90. * Si non défini, c'est le nom de propriété qui est utilisé
  91. */
  92. label: {
  93. type: String,
  94. required: false,
  95. default: null,
  96. },
  97. /**
  98. * Définit si le champ est en lecture seule
  99. */
  100. readonly: {
  101. type: Boolean,
  102. required: false,
  103. },
  104. /**
  105. * Règles de validation
  106. * @see https://vuetify.cn/en/components/forms/#validation-with-submit-clear
  107. */
  108. rules: {
  109. type: Array,
  110. required: false,
  111. default: () => [],
  112. },
  113. /**
  114. * Le champ est-il actuellement en état d'erreur
  115. */
  116. error: {
  117. type: Boolean,
  118. required: false,
  119. },
  120. /**
  121. * Si le champ est en état d'erreur, quel est le message d'erreur?
  122. */
  123. errorMessage: {
  124. type: String,
  125. required: false,
  126. default: null,
  127. },
  128. /**
  129. * @see https://vuetifyjs.com/en/api/v-autocomplete/#props-variant
  130. */
  131. variant: {
  132. type: String as PropType<
  133. | 'filled'
  134. | 'outlined'
  135. | 'plain'
  136. | 'underlined'
  137. | 'solo'
  138. | 'solo-inverted'
  139. | 'solo-filled'
  140. | undefined
  141. >,
  142. required: false,
  143. default: 'outlined',
  144. },
  145. })
  146. const showMenuTime = ref(false)
  147. const showMenuDate = ref(false)
  148. const _useDate = useDate()
  149. const { fieldViolations, updateViolationState } = useFieldViolation(props.field)
  150. const dateModel = computed(() =>
  151. props.modelValue ? new Date(props.modelValue) : undefined,
  152. )
  153. const time = computed(() =>
  154. props.modelValue
  155. ? _useDate.format(new Date(props.modelValue), 'fullTime24h')
  156. : undefined,
  157. )
  158. const emit = defineEmits(['update:model-value'])
  159. const onUpdateDate = (event: string) => {
  160. updateViolationState()
  161. const date = DateUtils.combineDateAndTime(event, time.value)
  162. emit('update:model-value', DateUtils.toIsoUtcOffset(date))
  163. }
  164. const onUpdateTime = (event: string) => {
  165. updateViolationState()
  166. const date = DateUtils.combineDateAndTime(dateModel.value, event)
  167. emit('update:model-value', DateUtils.toIsoUtcOffset(date))
  168. }
  169. onBeforeUnmount(() => {
  170. updateViolationState()
  171. })
  172. </script>
  173. <style scoped lang="scss"></style>