121 lines
3.1 KiB
Vue
121 lines
3.1 KiB
Vue
<template>
|
|
<div id="timeField" class="input input-sm input-bordered flex px-3 py-0">
|
|
<div class="grow">
|
|
<input
|
|
ref="timeInput"
|
|
:value="secToTime(props.modelValue)"
|
|
type="text"
|
|
pattern="([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\.[0-9]{1,3})?"
|
|
class="w-full px-1 py-0"
|
|
@click="setCursorPos"
|
|
@change="$emit('update:modelValue', timeToSec($event))"
|
|
/>
|
|
</div>
|
|
|
|
<div class="w-auto">
|
|
<div class="flex flex-col text-xs py-[2px]">
|
|
<button
|
|
class="bg-base-300 hover:bg-base-300/50 px-1 text-[9px] h-[13px] rounded-t"
|
|
tabindex="0"
|
|
@click="countUp"
|
|
>
|
|
<i class="bi-chevron-up" />
|
|
</button>
|
|
<button class="bg-base-300 hover:bg-base-300/50 px-1 text-[9px] h-[13px] rounded-b" @click="countDown">
|
|
<i class="bi-chevron-down" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<script setup lang="ts">
|
|
const emit = defineEmits(['update:modelValue'])
|
|
|
|
const props = defineProps({
|
|
modelValue: {
|
|
type: Number,
|
|
required: true,
|
|
},
|
|
})
|
|
|
|
const timeInput = ref()
|
|
const cursorPos = ref(8)
|
|
|
|
function secToTime(sec: number) {
|
|
const hours = Math.floor(sec / 3600)
|
|
sec %= 3600
|
|
const minutes = Math.floor(sec / 60)
|
|
const seconds = Math.floor(sec % 60)
|
|
const ms = Math.round((sec - Math.floor(sec)) * 1000) / 1000
|
|
const secFmt = (seconds + ms).toFixed(3)
|
|
|
|
const m = String(minutes).padStart(2, '0')
|
|
const h = String(hours).padStart(2, '0')
|
|
const s = secFmt.padStart(6, '0')
|
|
|
|
return `${h}:${m}:${s}`
|
|
}
|
|
|
|
function timeToSec(event: any) {
|
|
const time = event.target?.value ?? 0
|
|
|
|
const [h, m, s] = time.split(':').map((val: string) => Number(val) || 0)
|
|
|
|
return h * 3600 + m * 60 + s
|
|
}
|
|
|
|
function setCursorPos() {
|
|
cursorPos.value = timeInput.value?.selectionStart
|
|
}
|
|
|
|
function countUp() {
|
|
let count = 0
|
|
|
|
if (cursorPos.value && cursorPos.value >= 6) {
|
|
count = 1
|
|
} else if (cursorPos.value && cursorPos.value >= 3) {
|
|
count = 60
|
|
} else {
|
|
count = 3600
|
|
}
|
|
|
|
emit('update:modelValue', props.modelValue + count)
|
|
|
|
nextTick(() => {
|
|
timeInput.value?.focus()
|
|
timeInput.value?.setSelectionRange(cursorPos.value, cursorPos.value)
|
|
})
|
|
}
|
|
|
|
function countDown() {
|
|
let sec = props.modelValue
|
|
let count = 0
|
|
|
|
if (cursorPos.value && cursorPos.value >= 6) {
|
|
count = 1
|
|
} else if (cursorPos.value && cursorPos.value >= 3) {
|
|
count = 60
|
|
} else {
|
|
count = 3600
|
|
}
|
|
|
|
sec -= count
|
|
|
|
if (sec < 0) {
|
|
emit('update:modelValue', 0)
|
|
} else {
|
|
emit('update:modelValue', sec)
|
|
}
|
|
|
|
nextTick(() => {
|
|
timeInput.value?.focus()
|
|
timeInput.value?.setSelectionRange(cursorPos.value, cursorPos.value)
|
|
})
|
|
}
|
|
</script>
|
|
<style scoped>
|
|
#timeField:has(> div > input:invalid) {
|
|
border: red solid 1px;
|
|
}
|
|
</style>
|