0
0
Fork 0

feat: rework VnInputTime and fix VnInputDate bugs

This commit is contained in:
Alex Moreno 2024-07-02 08:06:31 +02:00
parent 938389de2e
commit cb5c33dcc9
4 changed files with 99 additions and 106 deletions

View File

@ -7,6 +7,7 @@ import { useArrayData } from 'composables/useArrayData';
import VnSelect from 'components/common/VnSelect.vue'; import VnSelect from 'components/common/VnSelect.vue';
import VnInput from 'components/common/VnInput.vue'; import VnInput from 'components/common/VnInput.vue';
import VnInputDate from 'components/common/VnInputDate.vue'; import VnInputDate from 'components/common/VnInputDate.vue';
import VnInputTime from 'components/common/VnInputTime.vue';
import VnTableColumn from 'components/VnTable/VnColumn.vue'; import VnTableColumn from 'components/VnTable/VnColumn.vue';
const $props = defineProps({ const $props = defineProps({
@ -75,6 +76,17 @@ const components = {
}, },
forceAttrs, forceAttrs,
}, },
time: {
component: markRaw(VnInputTime),
event: updateEvent,
attrs: {
...defaultAttrs,
disable: !$props.isEditable,
},
forceAttrs: {
label: $props.showLabel && $props.column.label,
},
},
checkbox: { checkbox: {
component: markRaw(QCheckbox), component: markRaw(QCheckbox),
event: updateEvent, event: updateEvent,

View File

@ -5,10 +5,6 @@ import { useI18n } from 'vue-i18n';
const model = defineModel({ type: String }); const model = defineModel({ type: String });
const $props = defineProps({ const $props = defineProps({
readonly: {
type: Boolean,
default: false,
},
isOutlined: { isOutlined: {
type: Boolean, type: Boolean,
default: false, default: false,
@ -48,6 +44,7 @@ const formattedDate = computed({
return date.formatDate(new Date(model.value), dateFormat); return date.formatDate(new Date(model.value), dateFormat);
}, },
set(value) { set(value) {
if (value == model.value) return;
let newDate; let newDate;
if (value) { if (value) {
// parse input // parse input
@ -97,12 +94,18 @@ watch(
v-bind="{ ...$attrs, ...styleAttrs }" v-bind="{ ...$attrs, ...styleAttrs }"
:class="{ required: $attrs.required }" :class="{ required: $attrs.required }"
:rules="$attrs.required ? [requiredFieldRule] : null" :rules="$attrs.required ? [requiredFieldRule] : null"
:clearable="false"
> >
<template #append> <template #append>
<QIcon <QIcon
name="close" name="close"
size="xs" size="xs"
v-if="hover && model && !readonly" v-if="
($attrs.clearable != undefined || $attrs.clearable) &&
hover &&
model &&
!$attrs.disable
"
@click=" @click="
model = null; model = null;
isPopupOpen = false; isPopupOpen = false;
@ -132,13 +135,3 @@ watch(
</QInput> </QInput>
</div> </div>
</template> </template>
<style lang="scss">
.vn-input-date.q-field--standard.q-field--readonly .q-field__control:before {
border-bottom-style: solid;
}
.vn-input-date.q-field--outlined.q-field--readonly .q-field__control:before {
border-style: solid;
}
</style>

View File

@ -1,14 +1,11 @@
<script setup> <script setup>
import { computed, ref } from 'vue'; import { watch, computed, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import isValidDate from 'filters/isValidDate'; import { date } from 'quasar';
const model = defineModel({ type: String });
const props = defineProps({ const props = defineProps({
modelValue: { timeOnly: {
type: String,
default: null,
},
readonly: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
@ -17,44 +14,33 @@ const props = defineProps({
default: false, default: false,
}, },
}); });
const emit = defineEmits(['update:modelValue']);
const { t } = useI18n(); const { t } = useI18n();
const requiredFieldRule = (val) => !!val || t('globals.fieldRequired'); const requiredFieldRule = (val) => !!val || t('globals.fieldRequired');
const value = computed({ const dateFormat = 'HH:mm';
const isPopupOpen = ref();
const hover = ref();
const formattedTime = computed({
get() { get() {
return props.modelValue; if (!model.value || model.value?.length <= 5) return model.value;
return dateToTime(model.value);
}, },
set(value) { set(value) {
const [hours, minutes] = value.split(':'); if (value == model.value) return;
const date = new Date(props.modelValue); let time = value;
date.setHours(Number.parseInt(hours) || 0, Number.parseInt(minutes) || 0, 0, 0); if (time) {
emit('update:modelValue', value ? date.toISOString() : null); if (time?.length > 5) time = dateToTime(time);
if (!props.timeOnly) {
const hours = time.split(':');
const date = new Date();
date.setHours(hours[0], hours[1], 0);
time = date.toISOString();
}
}
model.value = time;
}, },
}); });
const isPopupOpen = ref(false);
const onDateUpdate = (date) => {
internalValue.value = date;
};
const save = () => {
value.value = internalValue.value;
};
const formatTime = (dateString) => {
if (!dateString || !isValidDate(dateString)) {
return '';
}
const date = new Date(dateString || '');
return date.toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
});
};
const internalValue = ref(formatTime(value));
const styleAttrs = computed(() => { const styleAttrs = computed(() => {
return props.isOutlined return props.isOutlined
? { ? {
@ -64,64 +50,66 @@ const styleAttrs = computed(() => {
} }
: {}; : {};
}); });
function dateToTime(newDate) {
return date.formatDate(new Date(newDate), dateFormat);
}
watch(
() => model.value,
(val) => (formattedTime.value = val),
{ immediate: true }
);
</script> </script>
<template> <template>
<QInput <div @mouseover="hover = true" @mouseleave="hover = false">
class="vn-input-time" <QInput
readonly class="vn-input-time"
:model-value="formatTime(value)" mask="##:##"
v-bind="{ ...$attrs, ...styleAttrs }" placeholder="--:--"
:class="{ required: $attrs.required }" v-model="formattedTime"
:rules="$attrs.required ? [requiredFieldRule] : null" v-bind="{ ...$attrs, ...styleAttrs }"
@click="isPopupOpen = true" :class="{ required: $attrs.required }"
> style="min-width: 100px"
<template #append> :rules="$attrs.required ? [requiredFieldRule] : null"
<QIcon name="Schedule" class="cursor-pointer"> >
<QPopupProxy <template #append>
v-model="isPopupOpen" <QIcon
cover name="close"
transition-show="scale" size="xs"
transition-hide="scale" v-if="
:no-parent-event="props.readonly" ($attrs.clearable != undefined || $attrs.clearable) &&
> hover &&
<QTime model &&
:format24h="false" !$attrs.disable
:model-value="formatTime(value)" "
@update:model-value="onDateUpdate" @click="
> model = null;
<div class="row items-center justify-end q-gutter-sm"> isPopupOpen = false;
<QBtn "
:label="t('Cancel')" />
color="primary" <QIcon name="Schedule" class="cursor-pointer" />
flat </template>
v-close-popup <QMenu
/> transition-show="scale"
<QBtn transition-hide="scale"
label="Ok" v-model="isPopupOpen"
color="primary" anchor="bottom left"
flat self="top start"
@click="save" :no-focus="true"
v-close-popup >
/> <QTime
</div> :format24h="false"
</QTime> v-model="formattedTime"
</QPopupProxy> mask="HH:mm"
</QIcon> landscape
</template> now-btn
</QInput> />
</QMenu>
</QInput>
</div>
</template> </template>
<style lang="scss">
.vn-input-time.q-field--standard.q-field--readonly .q-field__control:before {
border-bottom-style: solid;
}
.vn-input-time.q-field--outlined.q-field--readonly .q-field__control:before {
border-style: solid;
}
</style>
<i18n> <i18n>
es: es:
Cancel: Cancelar Cancel: Cancelar

View File

@ -74,7 +74,7 @@ const agencyOptions = ref([]);
type="number" type="number"
min="0" min="0"
/> />
<VnInputTime v-model="data.hour" :label="t('Closing')" clearable /> <VnInputTime v-model="data.hour" :label="t('Closing')" />
</VnRow> </VnRow>
<VnRow class="row q-gutter-md q-mb-md"> <VnRow class="row q-gutter-md q-mb-md">