shape onModel improvements; vline fixes; time entry; couple bugs remain with dca dragging

This commit is contained in:
Tim
2024-04-19 19:51:06 -04:00
parent 1579060024
commit 59342e2e26
9 changed files with 457 additions and 144 deletions

View File

@@ -0,0 +1,276 @@
<template>
<div class="d-flex root">
<!--
<vue-scroll-picker :options="yearMonthItems" v-model="yearMonth" class="picker"/>
<vue-scroll-picker :options="wdItems" v-model="day" class="picker"/>
-->
<!-- <v-select :items="yearMonthItems" v-model="yearMonthItem"/>-->
<!-- <v-text-field v-model="day"/>-->
<!--
<v-tooltip v-model="showPicker">
<v-date-picker :show-adjacent-months="true" v-model="now"/>
</v-tooltip>
-->
<v-text-field type="number" v-model="year"
rounded="0" :hide-details="hideDetails" single-line class="all year" maxlength="4"/>
<!-- <v-text-field type="number" min="1" max="31" v-model="day" :label="wdFormat.format(day)"-->
<!-- :hide-details="hideDetails" style="min-width: 3em; width: 3em" class="all month"/>-->
<v-select v-model="month" :items="monthItems"
rounded="0" :hide-details="hideDetails" single-line class="all month"/>
<v-text-field type="number" v-model="day"
rounded="0" :hide-details="hideDetails" single-line class="all year"
min="1" :max="daysInMonth(...yearMonth)" maxlength="2"/>
<v-text-field type="time" v-model="time"
rounded="0" :hide-details="hideDetails" single-line class="all"/>
</div>
</template>
<script setup>
import {useStore} from "@/store/store";
import {computed, nextTick, ref} from "vue";
import {VueScrollPicker} from "vue-scroll-picker";
import {useDate} from "vuetify";
import {mixin} from "@/common.js";
const s = useStore()
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
const showPicker = ref(false)
const hideDetails = true
const date = useDate()
const now = computed(()=>new Date(1000*props.modelValue))
const dRef = ref(s.utc ? now.value.getUTCDate() : now.value.getDate())
const ymRef = ref([date.getYear(now.value), date.getMonth(now.value)])
const year = computed({
get() { return date.getYear(now.value) },
set(v) { update({year:v}) }
})
const month = computed({
get() { return date.getMonth(now.value) },
set(v) { update({month:v}) }
})
const day = computed({
get() { return now.value.getDate() },
set(v) { update({day:v}) },
})
const time = computed({
get() {
let hour, min
if( s.utc ) {
hour = now.value.getUTCHours()
min = now.value.getUTCMinutes()
}
else {
hour = now.value.getHours()
min = now.value.getMinutes()
}
return hour.toString().padStart(2,'0') + ':' + min.toString().padStart(2,'0')
},
set(v) {
const [hour,minute] = v.split(':')
update({hour:hour, minute:minute})
}
})
const curYearMonth = computed(()=>[date.getYear(now.value), date.getMonth(now.value)])
function extendPast(ms) {
console.log('extend past', ms)
const before = []
let cur = ms.length ? ms[0] : curYearMonth.value
for (let i=0; i<12; i++) {
cur = prevMonth(...cur)
before.push(cur)
}
before.reverse()
console.log('extended', before)
return [...before, ...ms]
}
function extendFuture(ms) {
console.log('extend future', ms)
const after = []
let cur = ms.length ? ms[ms.length-1] : curYearMonth.value
for (let i=0; i<12; i++) {
cur = nextMonth(...cur)
after.push(cur)
}
console.log('extended by', after)
return [...ms, ...after]
}
function dtFormat(format) {
return new Intl.DateTimeFormat(s.utc ? 'utc':undefined, format)
}
// todo utc
const yFormat = dtFormat({year:'numeric'})
const mFormat = dtFormat({month: 'long'})
const ymFormat = dtFormat({year:'numeric', month: 'long'})
const wdFormat = dtFormat({weekday:'short'})
const dFormat = dtFormat({day:'numeric'})
const monthItems = []
for( let i=0; i<12; i++ )
monthItems.push({value: i, title: mFormat.format(new Date(0, i))})
function ymItem(ym) {
const d = new Date(...ym);
const name = yFormat.format(d) + ' ' + mFormat.format(d)
// return {title: name, value: ym} // v-select
return {name, value: ym} // vue-scroll-picker
}
function wdItem(ym, day) {
const d = new Date(...ym, day)
const name = dFormat.format(d) + ' ' + wdFormat.format(d)
return {name, value: day}
}
const wdItems = computed(()=>{
const ym = yearMonth.value
const wds = []
for (let d=1; d<=daysInMonth(...yearMonth.value); d++)
wds.push(wdItem(ym,d))
return wds
})
const yearMonth = computed({
get() { return ymRef.value },
set(v) {
const [y, m] = v
const lastDay = daysInMonth(y,m);
const d = now.value.getDate() <= lastDay ? now.value.getDate() : lastDay
console.log('update yearmonth', v)
update({year:y, month:m, day:d})
},
})
const monthOptions = ref(extendFuture(extendPast([yearMonth.value])))
const yearMonthItems = computed({
get() {return monthOptions.value.map((ym) => ymItem(ym))},
set(v) {yearMonth.value = v}
})
function daysInMonth(year, month) {
return new Date(year, month+1, 0).getDate();
}
const dayItems = computed(()=>{
const days = []
for (let i=1; i<=daysInMonth(...yearMonth.value); i++)
days.push(i)
return days
})
function nextMonth( year, month ) {
month++
if( month===12 ) {
month = 0
year++
}
return [year, month]
}
function prevMonth( year, month ) {
month--
if( month===-1 ) {
month = 11
year--
}
return [year, month]
}
function update(fields={}) {
console.error('update', fields)
if (!Object.keys(fields).length) return
if (newValue===null) {
newValue = {}
nextTick(doUpdate)
}
mixin(newValue, fields)
console.log('triggering update', fields)
}
function doUpdate() {
console.log('doUpdate')
let dirty = false
if (newValue.year===undefined)
newValue.year = date.getYear(now.value)
else
dirty ||= newValue.year !== date.getYear(now.value)
if (newValue.month===undefined)
newValue.month = date.getMonth(now.value)
else
dirty ||= newValue.month !== date.getMonth(now.value)
if (newValue.day===undefined)
newValue.day = now.value.getDate()
else
dirty ||= newValue.day !== now.value.getDate()
if (newValue.hour===undefined)
newValue.hour = date.getHours(now.value)
else
dirty ||= newValue.hour !== date.getHours(now.value)
if (newValue.minute===undefined)
newValue.minute = date.getMinutes(now.value)
else
dirty ||= newValue.minute !== date.getMinutes(now.value)
if (dirty) {
const d = s.utc ?
new Date(Date.UTC(newValue.year, newValue.month, newValue.day, newValue.hour, newValue.minute)) :
new Date(newValue.year, newValue.month, newValue.day, newValue.hour, newValue.minute)
const ts = Math.round(d.getTime() / 1000);
console.log('doUpdate value', ts)
newValue = null
emit('update:modelValue', ts)
}
}
let newValue = null
</script>
<style scoped lang="scss">
.root {
$height: 3.3em;
margin-bottom: 0;
height: $height;
min-height: $height;
max-height: $height;
overflow-y: hidden;
}
.year {
width: 6em;
max-width: 6em;
min-width: 6em;
}
.month {
width: 10em;
max-width: 10em;
min-width: 5em;
}
.day {
}
.picker {
width: 8em;
height: 2em;
}
</style>