forked from verdnatura/salix-front
feat: rework VnInputTime and fix VnInputDate bugs
This commit is contained in:
parent
938389de2e
commit
cb5c33dcc9
|
@ -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,
|
||||||
|
|
|
@ -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>
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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">
|
||||||
|
|
Loading…
Reference in New Issue