Files
web/app/components/datepicker/Datepicker.vue
2026-05-27 09:17:52 +07:00

168 lines
3.8 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 px-2 w-xs">
<PickDay
v-bind="{ date, mindate, 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>
import PickDay from "@/components/datepicker/PickDay.vue";
const props = defineProps({
record: Object,
attr: String,
position: String,
mindate: [Date, String],
maxdate: [Date, String],
disabled: Boolean,
});
const emit = defineEmits(["date"]);
const { $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);
const 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>