166 lines
3.7 KiB
Vue
166 lines
3.7 KiB
Vue
<template>
|
|
<div
|
|
class="control has-icons-left"
|
|
ref="datepickerRoot"
|
|
>
|
|
<div :class="['dropdown w-full', pos, focused && 'is-active']">
|
|
<div class="dropdown-trigger w-full">
|
|
<input
|
|
:disabled="disabled"
|
|
:class="['input', error && 'is-danger', disabled && 'has-text-dark']"
|
|
type="text"
|
|
placeholder="DD/MM/YYYY"
|
|
maxlength="10"
|
|
@focus="setFocus"
|
|
@blur="lostFocus"
|
|
@keyup.enter="pressEnter"
|
|
@keyup="checkDate"
|
|
v-model="show"
|
|
/>
|
|
</div>
|
|
<div
|
|
class="dropdown-menu"
|
|
role="menu"
|
|
@click="doClick()"
|
|
>
|
|
<div class="dropdown-content">
|
|
<PickDay
|
|
v-bind="{ date, maxdate }"
|
|
@date="selectDate"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<span class="icon is-left">
|
|
<Icon
|
|
name="material-symbols:calendar-today-outline-rounded"
|
|
:size="21"
|
|
:class="focused ? 'has-text-primary' : 'has-text-grey'"
|
|
/>
|
|
</span>
|
|
</div>
|
|
</template>
|
|
<script setup>
|
|
const props = defineProps({
|
|
record: Object,
|
|
attr: String,
|
|
position: String,
|
|
mindate: String,
|
|
maxdate: String,
|
|
disabled: Boolean,
|
|
});
|
|
|
|
const emit = defineEmits(["date"]);
|
|
const { $id, $copy, $dayjs, $empty } = useNuxtApp();
|
|
|
|
const date = ref();
|
|
const show = ref();
|
|
const error = ref(false);
|
|
const focused = ref(false);
|
|
const count1 = ref(0);
|
|
const count2 = ref(0);
|
|
const pos = ref();
|
|
const datepickerRoot = useTemplateRef("datepickerRoot");
|
|
|
|
function getPos() {
|
|
switch (props.position) {
|
|
case "is-top-left":
|
|
pos.value = "is-up is-left";
|
|
break;
|
|
case "is-top-right":
|
|
pos.value = "is-up is-right";
|
|
break;
|
|
case "is-bottom-left":
|
|
pos.value = "is-left";
|
|
break;
|
|
case "is-bottom-right":
|
|
pos.value = "is-right";
|
|
break;
|
|
}
|
|
}
|
|
|
|
function initializeDate() {
|
|
if (props.record) {
|
|
date.value = props.record[props.attr] ? $copy(props.record[props.attr]) : undefined;
|
|
if (date.value) show.value = $dayjs(date.value).format("L");
|
|
}
|
|
}
|
|
|
|
function pressEnter() {
|
|
checkDate();
|
|
if (!error.value) focused.value = false;
|
|
}
|
|
|
|
function setFocus() {
|
|
focused.value = true;
|
|
count1.value = 0;
|
|
count2.value = 0;
|
|
}
|
|
|
|
function lostFocus() {
|
|
setTimeout(() => {
|
|
if (focused.value && count1.value === 0) focused.value = false;
|
|
}, 200);
|
|
}
|
|
|
|
function processEvent(event) {
|
|
count2.value += 1;
|
|
const isClickInside = datepickerRoot.value.contains(event.target);
|
|
if (!isClickInside && focused.value) {
|
|
if (count2.value - 1 !== count1.value) {
|
|
focused.value = false;
|
|
count1.value = 0;
|
|
count2.value = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
function doClick() {
|
|
count1.value += 1;
|
|
}
|
|
|
|
function selectDate(v) {
|
|
date.value = v;
|
|
show.value = $dayjs(v).format("L");
|
|
emit("date", date.value);
|
|
if (focused.value) focused.value = false;
|
|
count1.value = 0;
|
|
count2.value = 0;
|
|
}
|
|
|
|
function getDate(value) {
|
|
let v = value.replace(/\D/g, "").slice(0, 10);
|
|
if (v.length >= 5) {
|
|
return `${v.slice(0, 2)}/${v.slice(2, 4)}/${v.slice(4)}`;
|
|
} else if (v.length >= 3) {
|
|
return `${v.slice(0, 2)}/${v.slice(2)}`;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
function checkDate() {
|
|
if (!focused.value) setFocus();
|
|
error.value = false;
|
|
date.value = undefined;
|
|
if ($empty(show.value)) return emit("date", null);
|
|
show.value = getDate(show.value);
|
|
let val = `${show.value.substring(6, 10)}-${show.value.substring(3, 5)}-${show.value.substring(0, 2)}`;
|
|
if ($dayjs(val, "YYYY-MM-DD", true).isValid()) {
|
|
date.value = val;
|
|
emit("date", date.value);
|
|
} else error.value = true;
|
|
}
|
|
|
|
onMounted(() => {
|
|
getPos();
|
|
initializeDate();
|
|
});
|
|
|
|
watch(
|
|
() => props.record,
|
|
() => {
|
|
initializeDate();
|
|
},
|
|
);
|
|
</script>
|