add custom TimePicker
This commit is contained in:
parent
14afe61e12
commit
bbe3b56f23
120
components/TimePicker.vue
Normal file
120
components/TimePicker.vue
Normal file
@ -0,0 +1,120 @@
|
||||
<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>
|
@ -56,9 +56,6 @@ export default {
|
||||
file: 'Datei',
|
||||
play: 'Abspielen',
|
||||
title: 'Titel',
|
||||
timeDuration: 'Dauerzeit (in Sekunden)',
|
||||
timeIn: 'Eintrittszeit (in Sekunden)',
|
||||
timeOut: 'Austrittszeit (in Sekunden)',
|
||||
duration: 'Dauer',
|
||||
in: 'Eingang',
|
||||
out: 'Ausgang',
|
||||
|
@ -56,9 +56,6 @@ export default {
|
||||
file: 'File',
|
||||
play: 'Play',
|
||||
title: 'Title',
|
||||
timeDuration: 'Duration time (in seconds)',
|
||||
timeIn: 'Entry time (in seconds)',
|
||||
timeOut: 'Exit time (in seconds)',
|
||||
duration: 'Duration',
|
||||
in: 'In',
|
||||
out: 'Out',
|
||||
|
@ -56,9 +56,6 @@ export default {
|
||||
file: 'Arquivo',
|
||||
play: 'Play',
|
||||
title: 'Título',
|
||||
timeDuration: 'Tempo de duração (em segundos)',
|
||||
timeIn: 'Tempo de entrada (em segundos)',
|
||||
timeOut: 'Tempo de saída (em segundos)',
|
||||
duration: 'Duração',
|
||||
in: 'Início',
|
||||
out: 'Fim',
|
||||
|
@ -129,27 +129,23 @@
|
||||
</label>
|
||||
<label class="form-control w-auto mt-auto">
|
||||
<div class="label">
|
||||
<span class="label-text">{{ $t('player.timeIn') }}</span>
|
||||
<span class="label-text">{{ $t('player.in') }}</span>
|
||||
</div>
|
||||
<input v-model.number="newSource.in" type="number" class="input input-sm input-bordered w-auto" />
|
||||
<TimePicker v-model="newSource.in" />
|
||||
</label>
|
||||
|
||||
<label class="form-control w-auto mt-auto">
|
||||
<div class="label">
|
||||
<span class="label-text">{{ $t('player.timeOut') }}</span>
|
||||
<span class="label-text">{{ $t('player.out') }}</span>
|
||||
</div>
|
||||
<input v-model.number="newSource.out" type="number" class="input input-sm input-bordered w-auto" />
|
||||
<TimePicker v-model="newSource.out" />
|
||||
</label>
|
||||
|
||||
<label class="form-control w-auto mt-auto">
|
||||
<div class="label">
|
||||
<span class="label-text">{{ $t('player.timeDuration') }}</span>
|
||||
<span class="label-text">{{ $t('player.duration') }}</span>
|
||||
</div>
|
||||
<input
|
||||
v-model.number="newSource.duration"
|
||||
type="number"
|
||||
class="input input-sm input-bordered w-auto"
|
||||
/>
|
||||
<TimePicker v-model="newSource.duration" />
|
||||
</label>
|
||||
|
||||
<label class="form-control w-auto mt-auto">
|
||||
|
Loading…
x
Reference in New Issue
Block a user