mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 22:39:34 +00:00
team table, create team modal, delete team modal
This commit is contained in:
1 parent
0e33d86c98
commit
f6d0764969
24 files changed
+1750
-886
No files matched your search
@@ -1,326 +1,220 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-sheet tile height="54" color="grey lighten-3" class="d-flex">
|
||||
<v-btn icon class="ma-2" @click="$refs.calendar.prev()">
|
||||
<v-icon>mdi-chevron-left</v-icon>
|
||||
</v-btn>
|
||||
<v-select v-model="type" :items="types" dense outlined hide-details class="ma-2" label="type"></v-select>
|
||||
<v-select v-model="mode" :items="modes" dense outlined hide-details label="event-overlap-mode" class="ma-2"></v-select>
|
||||
<v-select v-model="weekday" :items="weekdays" dense outlined hide-details label="weekdays" class="ma-2"></v-select>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon class="ma-2" @click="$refs.calendar.next()">
|
||||
<v-icon>mdi-chevron-right</v-icon>
|
||||
</v-btn>
|
||||
</v-sheet>
|
||||
<v-sheet height="600">
|
||||
<v-calendar ref="calendar" v-model="value" :weekdays="weekday" :type="type" :events="events" :event-overlap-mode="mode" :event-overlap-threshold="60" :event-color="getEventColor" :event-ripple="false" @change="getEvents" @mousedown:event="startDrag" @mousedown:time="startTime" @mousemove:time="mouseMove" @mouseup:time="endDrag" @mouseleave="cancelDrag">
|
||||
<template #event="{ event, timed }">
|
||||
<div class="pl-1" v-html="getEventHTML(event, timed)"></div>
|
||||
<div v-if="timed" class="v-event-drag-bottom" @mousedown.stop="extendBottom(event)"></div>
|
||||
</template>
|
||||
<template #day-body="{ date, week }">
|
||||
<div class="v-current-time" :class="{ first: date === week[0].date }" :style="{ top: nowY }">
|
||||
<div class="v-current-time-time">
|
||||
{{ nowTime }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</v-calendar>
|
||||
<!-- {{ lastEvent }} -->
|
||||
</v-sheet>
|
||||
<div class="calendar-wrapper">
|
||||
<Vue-cal
|
||||
:hide-view-selector="true"
|
||||
:hide-title-bar="true"
|
||||
:disable-views="['years', 'year', 'month', 'day']"
|
||||
:time-from="8 * 60"
|
||||
:time-to="24 * 60"
|
||||
:hide-weekends="true"
|
||||
:selected-date="new Date()"
|
||||
:onEventClick="taskClicked"
|
||||
:editable-events="vueCalConfig.editing"
|
||||
:events="events"
|
||||
:min-event-width="90"
|
||||
:overlaps-per-time-step="true"
|
||||
:time-cell-height="200"
|
||||
:min-cell-width="300"
|
||||
sticky-split-labels
|
||||
>
|
||||
<template v-slot:weekday-heading="{ heading }">
|
||||
<span class="d-flex align-center">
|
||||
<img v-if="getHeadingDate(heading.date) == 'Dnes'" :src="require('./_img/home-icon.svg')" class="mr-2">
|
||||
<p>{{ getHeadingDate(heading.date) }}</p>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template v-slot:time-cell="{ hours, minutes }">
|
||||
<span class="d-flex align-center justify-center">
|
||||
<p>{{hours}}:{{String(minutes).padStart(2, '0')}}</p>
|
||||
<div class="time-column-line"></div>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<template v-slot:event="{ event }">
|
||||
<div class="vuecal__event-title vuecal__event-title--edit"
|
||||
contenteditable
|
||||
@blur="event.title = $event.target.innerHTML"
|
||||
v-html="event.title" />
|
||||
<small class="vuecal__event-time">
|
||||
|
||||
<strong>Event start:</strong> <span>{{ event.start.formatTime("h O'clock") }}</span><br/>
|
||||
<strong>Event end:</strong> <span>{{ event.end.formatTime("h O'clock") }}</span>
|
||||
</small>
|
||||
</template>
|
||||
</Vue-cal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
// import VueCal from 'vue-cal'
|
||||
// import 'vue-cal/dist/vuecal.css'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
// VueCal,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
type: 'day',
|
||||
types: ['month', 'week', 'day', '4day'],
|
||||
mode: 'stack',
|
||||
modes: ['stack', 'column'],
|
||||
weekday: [0, 1, 2, 3, 4, 5, 6],
|
||||
weekdays: [
|
||||
{ text: 'Sun - Sat', value: [0, 1, 2, 3, 4, 5, 6] },
|
||||
{ text: 'Mon - Sun', value: [1, 2, 3, 4, 5, 6, 0] },
|
||||
{ text: 'Mon - Fri', value: [1, 2, 3, 4, 5] },
|
||||
{ text: 'Mon, Wed, Fri', value: [1, 3, 5] }
|
||||
events: [
|
||||
{
|
||||
start: '2022-11-21 8:00',
|
||||
end: '2022-11-21 13:30',
|
||||
title: 'Running Marathon',
|
||||
content: '<i class="icon material-icons">directions_run</i>',
|
||||
class: 'red',
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
start: '2022-11-21 9:00',
|
||||
end: '2022-11-21 11:00',
|
||||
title: 'Drink water!',
|
||||
content: '<i class="icon material-icons">local_drink</i>',
|
||||
class: 'green',
|
||||
id: 2
|
||||
},
|
||||
{
|
||||
start: '2022-11-21 10:00',
|
||||
end: '2022-11-21 12:00',
|
||||
title: 'Trip to India',
|
||||
content: '<i class="icon material-icons">flight</i>',
|
||||
class: 'blue',
|
||||
id: 3
|
||||
},
|
||||
{
|
||||
start: '2022-11-21 13:30',
|
||||
end: '2022-11-21 16:00',
|
||||
title: 'Trip to India',
|
||||
content: '<i class="icon material-icons">flight</i>',
|
||||
class: 'blue',
|
||||
id: 3
|
||||
},
|
||||
{
|
||||
start: '2022-11-22 11:00',
|
||||
end: '2022-11-22 13:00',
|
||||
title: 'Trip to India',
|
||||
content: '<i class="icon material-icons">flight</i>',
|
||||
class: 'yellow',
|
||||
id: 3
|
||||
}
|
||||
],
|
||||
value: '',
|
||||
events: [],
|
||||
colors: ['#2196F3', '#3F51B5', '#673AB7', '#00BCD4', '#4CAF50', '#FF9800', '#757575'],
|
||||
names: ['Meeting', 'Holiday', 'PTO', 'Travel', 'Event', 'Birthday', 'Conference', 'Party'],
|
||||
|
||||
dragEvent: null,
|
||||
dragStart: null,
|
||||
lastEvent: '',
|
||||
createEvent: null,
|
||||
createStart: null,
|
||||
extendOriginal: null,
|
||||
vueCalConfig: {
|
||||
editing: {
|
||||
title: false,
|
||||
drag: true,
|
||||
resize: false,
|
||||
delete: false,
|
||||
create: false
|
||||
}
|
||||
},
|
||||
|
||||
isMounted: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
nowY() {
|
||||
const cal = this.$refs.calendar
|
||||
if (!cal && !this.isMounted) {
|
||||
return -1
|
||||
}
|
||||
|
||||
return cal.timeToY(cal.times.now) + 'px'
|
||||
},
|
||||
|
||||
nowTime() {
|
||||
const cal = this.$refs.calendar
|
||||
if (!cal && !this.isMounted) {
|
||||
return -1
|
||||
}
|
||||
|
||||
return cal.formatTime(cal.times.now)
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const cal = this.$refs.calendar
|
||||
this.isMounted = true
|
||||
|
||||
// scroll to the current time
|
||||
const minutes = cal.times.now.hour * 60 + cal.times.now.minute
|
||||
const firstTime = Math.max(0, minutes - (minutes % 30) - 30)
|
||||
cal.scrollToTime(firstTime)
|
||||
|
||||
// every minute update the current time bar
|
||||
setInterval(() => cal.updateTimes(), 60 * 1000)
|
||||
},
|
||||
|
||||
methods: {
|
||||
getEvents({ start, end }) {
|
||||
const events = []
|
||||
getHeadingDate(value) {
|
||||
const date = new Date(value)
|
||||
|
||||
const min = new Date(`${start.date}T00:00:00`)
|
||||
const max = new Date(`${end.date}T23:59:59`)
|
||||
const days = (max.getTime() - min.getTime()) / 86400000
|
||||
const eventCount = this.rnd(days, days + 20)
|
||||
const today = new Date()
|
||||
const yesterday = new Date((new Date()).setDate(today.getDate() - 1))
|
||||
const tomorrow = new Date((new Date()).setDate(today.getDate() + 1))
|
||||
|
||||
for (let i = 0; i < eventCount; i++) {
|
||||
const allDay = this.rnd(0, 3) === 0
|
||||
const firstTimestamp = this.rnd(min.getTime(), max.getTime())
|
||||
const first = new Date(firstTimestamp - (firstTimestamp % 900000))
|
||||
const secondTimestamp = this.rnd(2, allDay ? 288 : 8) * 900000
|
||||
const second = new Date(first.getTime() + secondTimestamp)
|
||||
if (today.toLocaleDateString('sk-SK') === date.toLocaleDateString('sk-SK')) return "Dnes"
|
||||
if (yesterday.toLocaleDateString('sk-SK') === date.toLocaleDateString('sk-SK')) return "Včera"
|
||||
if (tomorrow.toLocaleDateString('sk-SK') === date.toLocaleDateString('sk-SK')) return "Zajtra"
|
||||
|
||||
events.push({
|
||||
name: this.names[this.rnd(0, this.names.length - 1)],
|
||||
start: this.formatDate(first, !allDay),
|
||||
end: this.formatDate(second, !allDay),
|
||||
color: this.colors[this.rnd(0, this.colors.length - 1)]
|
||||
})
|
||||
}
|
||||
return date.toLocaleDateString('sk-SK')
|
||||
},
|
||||
|
||||
this.events = events
|
||||
},
|
||||
getEventColor(event) {
|
||||
const rgb = parseInt(event.color.substring(1), 16)
|
||||
const r = (rgb >> 16) & 0xff
|
||||
const g = (rgb >> 8) & 0xff
|
||||
const b = (rgb >> 0) & 0xff
|
||||
|
||||
return event === this.dragEvent ? `rgba(${r}, ${g}, ${b}, 0.5)` : event === this.createEvent ? `rgba(${r}, ${g}, ${b}, 0.5)` : event.color
|
||||
},
|
||||
getEventHTML(event, timed) {
|
||||
const cal = this.$refs.calendar
|
||||
let name = event.name
|
||||
if (event.start.hasTime) {
|
||||
if (timed) {
|
||||
const showStart = event.start.hour < 12 && event.end.hour >= 12
|
||||
const start = cal.formatTime(event.start, showStart)
|
||||
const end = cal.formatTime(event.end, true)
|
||||
// const singline = diffMinutes(event.start, event.end) <= this.parsedEventOverlapThreshold
|
||||
const singline = event.end - event.start <= this.parsedEventOverlapThreshold
|
||||
const separator = singline ? ', ' : '<br>'
|
||||
return `<strong>${name}</strong>${separator}${start} - ${end}`
|
||||
} else {
|
||||
const time = this.formatTime(event.start, true)
|
||||
return `<strong>${time}</strong> ${name}`
|
||||
}
|
||||
}
|
||||
return name
|
||||
},
|
||||
rnd(a, b) {
|
||||
return Math.floor((b - a + 1) * Math.random()) + a
|
||||
},
|
||||
formatDate(a, withTime) {
|
||||
return withTime ? `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()} ${a.getHours()}:${a.getMinutes()}` : `${a.getFullYear()}-${a.getMonth() + 1}-${a.getDate()}`
|
||||
},
|
||||
eventMove(e) {
|
||||
console.log('eventMove', e)
|
||||
},
|
||||
startDrag(e) {
|
||||
if (e.event && e.timed) {
|
||||
this.dragEvent = e.event
|
||||
this.dragTime = null
|
||||
this.extendOriginal = null
|
||||
}
|
||||
|
||||
this.lastEvent = 'startDrag'
|
||||
},
|
||||
startTime(e) {
|
||||
const mouse = this.toDate(e)
|
||||
|
||||
if (this.dragEvent && this.dragTime === null) {
|
||||
const start = this.toDate(this.dragEvent.start)
|
||||
|
||||
this.dragTime = mouse.getTime() - start.getTime()
|
||||
} else {
|
||||
this.createStart = this.roundTime(mouse.getTime())
|
||||
this.createEvent = {
|
||||
name: '(no title)',
|
||||
start: this.toTimestamp(new Date(this.createStart)),
|
||||
end: this.toTimestamp(new Date(this.createStart)),
|
||||
color: this.colors[this.rnd(0, this.colors.length - 1)]
|
||||
}
|
||||
this.events.push(this.createEvent)
|
||||
}
|
||||
this.lastEvent = 'startTime'
|
||||
},
|
||||
extendBottom(event) {
|
||||
this.createEvent = event
|
||||
this.createStart = this.toDate(event.start).getTime()
|
||||
this.extendOriginal = event.end
|
||||
},
|
||||
mouseMoveEvent(e) {
|
||||
console.log('mouseMoveEvent', e)
|
||||
},
|
||||
mouseMove(e) {
|
||||
if (this.dragEvent && this.dragTime !== null) {
|
||||
const start = this.toDate(this.dragEvent.start)
|
||||
const end = this.toDate(this.dragEvent.end)
|
||||
const duration = end.getTime() - start.getTime()
|
||||
const mouse = this.toDate(e)
|
||||
|
||||
const newStartTime = mouse.getTime() - this.dragTime
|
||||
const newStart = new Date(this.roundTime(newStartTime))
|
||||
const newEnd = new Date(newStart.getTime() + duration)
|
||||
|
||||
this.dragEvent.start = this.toTimestamp(newStart)
|
||||
this.dragEvent.end = this.toTimestamp(newEnd)
|
||||
} else if (this.createEvent && this.createStart !== null) {
|
||||
const mouse = this.toDate(e).getTime()
|
||||
const mouseRounded = this.roundTime(mouse, false)
|
||||
const min = Math.min(mouseRounded, this.createStart)
|
||||
const max = Math.max(mouseRounded, this.createStart)
|
||||
|
||||
this.createEvent.start = this.toTimestamp(new Date(min))
|
||||
this.createEvent.end = this.toTimestamp(new Date(max))
|
||||
}
|
||||
},
|
||||
endDrag(e) {
|
||||
this.dragTime = null
|
||||
this.dragEvent = null
|
||||
this.createEvent = null
|
||||
this.createStart = null
|
||||
this.extendOriginal = null
|
||||
|
||||
this.lastEvent = 'endDrag'
|
||||
},
|
||||
cancelDrag(e) {
|
||||
if (this.createEvent) {
|
||||
if (this.extendOriginal) {
|
||||
this.createEvent.end = this.extendOriginal
|
||||
} else {
|
||||
const i = this.events.indexOf(this.createEvent)
|
||||
if (i !== -1) {
|
||||
this.events.splice(i, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.createEvent = null
|
||||
this.createStart = null
|
||||
this.dragTime = null
|
||||
this.dragEvent = null
|
||||
|
||||
this.lastEvent = 'cancelDrag'
|
||||
},
|
||||
roundTime(time, down = true) {
|
||||
const roundDownTime = 15 * 60 * 1000 // 15 minutes
|
||||
|
||||
return down ? time - (time % roundDownTime) : time + (roundDownTime - (time % roundDownTime))
|
||||
},
|
||||
toDate(tms) {
|
||||
return typeof tms === 'string' ? new Date(tms) : new Date(tms.year, tms.month - 1, tms.day, tms.hour, tms.minute)
|
||||
},
|
||||
toTimestamp(date) {
|
||||
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}`
|
||||
taskClicked(task) {
|
||||
console.log("task", task)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="sass" scoped>
|
||||
.v-calendar
|
||||
user-select: none
|
||||
-webkit-user-select: none
|
||||
.calendar-wrapper
|
||||
width: 100%
|
||||
overflow-x: scroll
|
||||
padding-top: 50px
|
||||
|
||||
.v-event-drag-bottom
|
||||
position: absolute
|
||||
left: 0
|
||||
right: 0
|
||||
bottom: 4px
|
||||
height: 4px
|
||||
cursor: ns-resize
|
||||
.vuecal
|
||||
transform: scale(1)
|
||||
|
||||
.v-event-drag-bottom::after
|
||||
display: none
|
||||
position: absolute
|
||||
left: 50%
|
||||
height: 4px
|
||||
border-top: 1px solid white
|
||||
border-bottom: 1px solid white
|
||||
width: 20px
|
||||
margin-left: -10px
|
||||
opacity: 0.8
|
||||
content: ''
|
||||
::v-deep
|
||||
|
||||
.v-event-timed:hover .v-event-drag-bottom::after
|
||||
display: block
|
||||
.vuecal__cells
|
||||
-ms-overflow-style: none
|
||||
scrollbar-width: none
|
||||
|
||||
.v-current-time
|
||||
height: 1px
|
||||
background-color: red
|
||||
position: absolute
|
||||
left: -1px
|
||||
right: 0
|
||||
pointer-events: none
|
||||
&::-webkit-scrollbar
|
||||
display: none
|
||||
|
||||
&.first::after
|
||||
content: ''
|
||||
position: absolute
|
||||
background-color: red
|
||||
width: 7px
|
||||
height: 7px
|
||||
border-radius: 3.5px
|
||||
margin-top: -3px
|
||||
margin-left: -3px
|
||||
.vuecal__body
|
||||
max-height: 100%
|
||||
overflow-y: scroll
|
||||
position: relative !important
|
||||
-ms-overflow-style: none
|
||||
scrollbar-width: none
|
||||
|
||||
&::-webkit-scrollbar
|
||||
display: none
|
||||
|
||||
.v-current-time-time
|
||||
display: none
|
||||
.weekday-label
|
||||
justify-content: start !important
|
||||
font-size: 24px
|
||||
font-weight: 700
|
||||
|
||||
.vuecal__weekdays-headings,
|
||||
.vuecal__cell:before
|
||||
border: none
|
||||
|
||||
&.first .v-current-time-time
|
||||
display: block
|
||||
position: absolute
|
||||
left: -60px
|
||||
color: red
|
||||
font-size: 10px
|
||||
padding: 1px
|
||||
background-color: white
|
||||
width: 50px
|
||||
height: 20px
|
||||
text-align: right
|
||||
top: -9px
|
||||
.vuecal__time-column
|
||||
width: 150px
|
||||
box-shadow: none !important
|
||||
|
||||
.time-column-line
|
||||
width: 40px
|
||||
height: 0
|
||||
border: 1px solid rgba(33, 33, 33, 0.08)
|
||||
margin-left: 10px
|
||||
|
||||
.vuecal__flex
|
||||
flex-wrap: nowrap !important
|
||||
|
||||
.vuecal__cell
|
||||
padding: 10px 10px 10px 0px
|
||||
|
||||
.vuecal__cell--today
|
||||
background-color: rgba(0, 0, 0, .02) !important
|
||||
|
||||
.vuecal:not(.vuecal--day-view) .vuecal__cell--selected:not(.vuecal__cell--today) ,
|
||||
.vuecal__cell--current:not(.vuecal__cell--today)
|
||||
background-color: white
|
||||
|
||||
.vuecal__event
|
||||
border-radius: 16px
|
||||
padding: 20px 10px
|
||||
text-align: left
|
||||
|
||||
.vuecal__event-title
|
||||
text-align: left
|
||||
|
||||
&:hover
|
||||
z-index: 10
|
||||
|
||||
&.red
|
||||
background: #FFC9C9 !important
|
||||
|
||||
&.green
|
||||
background: #E9FFE5 !important
|
||||
|
||||
&.blue
|
||||
background: #DADEF8 !important
|
||||
|
||||
&.yellow
|
||||
background: #F6ECD3 !important
|
||||
</style>
|
||||
Reference in new issue
Block a user