mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 14:29:34 +00:00
Merge branch 'main' of bitbucket.org:studiotem/jandl-taskmanager-app
This commit is contained in:
commit
bbc476f5cd
15 files changed
+305
-247
No files matched your search
@@ -7,8 +7,9 @@
|
|||||||
<td>{{ mastertask.name }}</td>
|
<td>{{ mastertask.name }}</td>
|
||||||
<td class="task-action">
|
<td class="task-action">
|
||||||
<div class="d-flex justify-start">
|
<div class="d-flex justify-start">
|
||||||
<img class="pencil-icon" :src="require('@/plugins/app/_img/icons/pencil.svg')" alt="pencil-icon" @click.stop="openEditMasterTaskModal(mastertask)">
|
<img class="pencil-icon" :src="require('@/plugins/app/_img/icons/pencil.svg')" alt="pencil-icon" @click.stop="openEditMasterTaskModal(mastertask, true)">
|
||||||
<img class="trash-icon" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="openDeleteMasterTaskModal(mastertask)">
|
<img class="pencil-icon ml-2" :src="require('@/plugins/app/_img/icons/eye.svg')" alt="eye-icon" @click.stop="openEditMasterTaskModal(mastertask, false)">
|
||||||
|
<img class="trash-icon ml-2" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="openDeleteMasterTaskModal(mastertask)">
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -36,8 +37,8 @@ export default {
|
|||||||
this.$events.emit('show-delete-master-task-modal', { mastertask })
|
this.$events.emit('show-delete-master-task-modal', { mastertask })
|
||||||
},
|
},
|
||||||
|
|
||||||
openEditMasterTaskModal(mastertask) {
|
openEditMasterTaskModal(mastertask, editMode) {
|
||||||
this.$events.emit('show-mastertask-modal', { mastertask, editMode: false })
|
this.$events.emit('show-mastertask-modal', { mastertask, editMode })
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,9 @@
|
|||||||
<div class="d-flex justify-start">
|
<div class="d-flex justify-start">
|
||||||
<img v-if="subtask.is_finished" class="pencil-icon is-finished" :src="require('@/plugins/app/_img/icons/checkmark.svg')" alt="checkmark-icon" @click.stop="clickCompleteTask(subtask)">
|
<img v-if="subtask.is_finished" class="pencil-icon is-finished" :src="require('@/plugins/app/_img/icons/checkmark.svg')" alt="checkmark-icon" @click.stop="clickCompleteTask(subtask)">
|
||||||
<img v-if="!subtask.is_finished" class="pencil-icon" :src="require('@/plugins/app/_img/icons/checkmark.svg')" alt="checkmark-icon" @click.stop="clickCompleteTask(subtask)">
|
<img v-if="!subtask.is_finished" class="pencil-icon" :src="require('@/plugins/app/_img/icons/checkmark.svg')" alt="checkmark-icon" @click.stop="clickCompleteTask(subtask)">
|
||||||
<img class="pencil-icon ml-2" :src="require('@/plugins/app/_img/icons/eye.svg')" alt="pencil-icon" @click.stop="openTaskModal(subtask)">
|
<img class="pencil-icon ml-2" :src="require('@/plugins/app/_img/icons/pencil.svg')" alt="pencil-icon" @click.stop="openTaskModal(subtask, true)">
|
||||||
<img class="trash-icon" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="openDeleteTaskModal(subtask)">
|
<img class="pencil-icon ml-2" :src="require('@/plugins/app/_img/icons/eye.svg')" alt="eye-icon" @click.stop="openTaskModal(subtask, false)">
|
||||||
|
<img class="trash-icon ml-2" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="openDeleteTaskModal(subtask)">
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -61,8 +62,8 @@ export default {
|
|||||||
this.$events.emit('show-delete-task-modal', { subtask })
|
this.$events.emit('show-delete-task-modal', { subtask })
|
||||||
},
|
},
|
||||||
|
|
||||||
openTaskModal(subtask) {
|
openTaskModal(subtask, editMode) {
|
||||||
this.$events.emit('show-subtask-modal', { subtask, editMode: false })
|
this.$events.emit('show-subtask-modal', { subtask, editMode })
|
||||||
},
|
},
|
||||||
|
|
||||||
async clickCompleteTask(subtask) {
|
async clickCompleteTask(subtask) {
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<form>
|
<div>
|
||||||
<A-search-result-mastertasks v-if="searchResults?.mastertasks" :mastertasks="searchResults.mastertasks"/>
|
<p v-if="!this.searchResults" class="px-3 py-3">{{ this.search?.length ? $t('Searching...') : $t('Type something') }}</p>
|
||||||
<A-search-result-subtasks v-if="searchResults?.subtasks" :subtasks="searchResults.subtasks" />
|
<p v-else-if="this.searchResults.error" class="px-3">{{ this.searchResults.error }}</p>
|
||||||
<A-search-result-team v-if="searchResults?.teams" :teams="searchResults.teams" />
|
|
||||||
</form>
|
<div v-else>
|
||||||
|
<A-search-result-mastertasks :mastertasks="searchResults.mastertasks"/>
|
||||||
|
<A-search-result-subtasks :subtasks="searchResults.subtasks" />
|
||||||
|
<A-search-result-team :teams="searchResults.teams" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -21,33 +26,59 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
searchResults: {},
|
searchResults: null,
|
||||||
search: ''
|
search: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.$events.on('onSearch', (search) => {
|
this.$events.on('onSearch', (search) => {
|
||||||
|
if (!search?.length)
|
||||||
|
return
|
||||||
|
|
||||||
this.search = search
|
this.search = search
|
||||||
|
this.onSearch(search)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
mounted() {
|
||||||
search(newVal) {
|
this.$events.on('on-subtask-edited', () => {
|
||||||
this.updateSearchResults(newVal)
|
this.onSearch(this.search, false)
|
||||||
}
|
})
|
||||||
|
|
||||||
|
this.$events.on('on-subtask-deleted', () => {
|
||||||
|
this.onSearch(this.search, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$events.on('on-mastertask-edited', () => {
|
||||||
|
this.onSearch(this.search, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$events.on('on-mastertask-deleted', () => {
|
||||||
|
this.onSearch(this.search, false)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
unmounted() {
|
||||||
|
this.$events.off('on-subtask-edited')
|
||||||
|
this.$events.off('on-subtask-deleted')
|
||||||
|
this.$events.off('on-mastertask-edited')
|
||||||
|
this.$events.off('on-mastertask-deleted')
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
updateSearchResults: debounce(async function (search) {
|
onSearch: debounce(async function (search, reset = true) {
|
||||||
try {
|
try {
|
||||||
|
if (reset)
|
||||||
|
this.searchResults = null
|
||||||
|
|
||||||
const { mastertasks, subtasks, teams} = await this.$axios.get_auth(`v1/search?q=${search}`)
|
const { mastertasks, subtasks, teams} = await this.$axios.get_auth(`v1/search?q=${search}`)
|
||||||
this.searchResults = {mastertasks: mastertasks.data, subtasks: subtasks.data, teams: teams.data}
|
this.searchResults = {mastertasks: mastertasks.data, subtasks: subtasks.data, teams: teams.data}
|
||||||
console.log(this.searchResults)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$toast.error(error)
|
this.$toast.error(error)
|
||||||
|
this.searchResults = {error}
|
||||||
}
|
}
|
||||||
}, 500)
|
}, 300)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -26,10 +26,11 @@
|
|||||||
<template v-slot:split-label="{ split }">
|
<template v-slot:split-label="{ split }">
|
||||||
<div class="w-100 h-100 d-flex flex-column">
|
<div class="w-100 h-100 d-flex flex-column">
|
||||||
<span v-if="split.date" class="d-flex align-center">
|
<span v-if="split.date" class="d-flex align-center">
|
||||||
<img v-if="getHeadingDate(split.date) == 'Dnes'" :src="require('@/plugins/app/_img/icons/home.svg')" class="mr-2">
|
<img v-if="split.isHomeoffice" :src="require('@/plugins/app/_img/icons/home.svg')" class="mr-2">
|
||||||
<p class="weekday-label">{{ getHeadingDate(split.date) }}</p>
|
<p class="weekday-label">{{ getHeadingDate(split.date) }}</p>
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="d-flex align-center">
|
<span v-else class="d-flex align-center">
|
||||||
|
<img v-if="split.isHomeoffice" :src="require('@/plugins/app/_img/icons/home.svg')" class="mr-2">
|
||||||
<p class="weekday-label">{{ split.name }}</p>
|
<p class="weekday-label">{{ split.name }}</p>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -64,15 +65,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="event.blocker?.type != 'home_office'" class="custom-event-body w-100 h-100 d-flex flex-column justify-space-between" :class="{'short-event' : getEventLength(event) <= 9000000, 'mini-event' : getEventLength(event) <= 5400000, 'micro-event' : getEventLength(event) <= 3600000}" :style="{backgroundColor: event.color || event.subtask.color}">
|
<div v-else-if="['subtask', 'blocker', 'adhoc', 'vacation', 'free_day'].includes(event.type)" class="custom-event-body w-100 h-100 d-flex flex-column justify-space-between" :class="{'short-event' : getEventLength(event) <= 9000000, 'mini-event' : getEventLength(event) <= 5400000, 'micro-event' : getEventLength(event) <= 3600000}" :style="{backgroundColor: event.color || event.subtask.color}">
|
||||||
<div class="event-content" :class="event.type || 'subtask'">
|
<div class="event-content" :class="{'is-blocker': event.isBlocker}">
|
||||||
<template v-if="event.type == 'blocker'">
|
<template v-if="event.type == 'subtask'">
|
||||||
<h3>{{ event.blocker.name }}</h3>
|
<small v-if="event.subtask.project_code" class="project-code">{{ event.subtask.project_code }}</small>
|
||||||
|
<h3>{{ event.subtask.master_task?.name || event.subtask.master_task }}</h3>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<small v-if="event.subtask.project_code" class="project-code">{{ event.subtask.project_code }}</small>
|
<h3>{{ event.blocker.name }}</h3>
|
||||||
<h3>{{ event.subtask.master_task?.name || event.subtask.master_task }}</h3>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="d-flex align-center event-details event-initials-wrapper">
|
<div class="d-flex align-center event-details event-initials-wrapper">
|
||||||
@@ -84,12 +85,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="event-footer d-flex">
|
<div class="event-footer d-flex">
|
||||||
<template v-if="event.type == 'blocker'">
|
<template v-if="event.type == 'adhoc'">
|
||||||
<v-btn rounded class="event-footer-button me-2" @click.stop="editBlocker(event)"><img :src="require('@/plugins/app/_img/icons/pencil.svg')" alt=""></v-btn>
|
<v-btn rounded class="event-footer-button me-2" @click.stop="editBlocker(event)"><img :src="require('@/plugins/app/_img/icons/pencil.svg')" alt=""></v-btn>
|
||||||
<v-btn rounded class="event-footer-button me-2" @click.stop="deleteBlocker(event)"><img :src="require('@/plugins/app/_img/icons/bin.svg')" alt=""></v-btn>
|
<v-btn rounded class="event-footer-button me-2" @click.stop="deleteBlocker(event)"><img :src="require('@/plugins/app/_img/icons/bin.svg')" alt=""></v-btn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else-if="event.type == 'subtask'">
|
||||||
<v-btn rounded class="event-footer-button me-2" :class="{'completed': event.subtask?.is_finished}" @click.stop="completeTask(event)"><img :src="require('@/plugins/app/_img/icons/checkmark.svg')" alt=""></v-btn>
|
<v-btn rounded class="event-footer-button me-2" :class="{'completed': event.subtask?.is_finished}" @click.stop="completeTask(event)"><img :src="require('@/plugins/app/_img/icons/checkmark.svg')" alt=""></v-btn>
|
||||||
<v-btn rounded class="event-footer-button me-2" @click.stop="editTask(event)"><img :src="require('@/plugins/app/_img/icons/eye.svg')" alt=""></v-btn>
|
<v-btn rounded class="event-footer-button me-2" @click.stop="editTask(event)"><img :src="require('@/plugins/app/_img/icons/eye.svg')" alt=""></v-btn>
|
||||||
<v-btn rounded class="event-footer-button me-2" @click.stop="deleteTask(event)"><img :src="require('@/plugins/app/_img/icons/bin.svg')" alt=""></v-btn>
|
<v-btn rounded class="event-footer-button me-2" @click.stop="deleteTask(event)"><img :src="require('@/plugins/app/_img/icons/bin.svg')" alt=""></v-btn>
|
||||||
@@ -209,11 +210,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
taskClicked(subtask) {
|
taskClicked(subtask) {
|
||||||
if (subtask.type == 'non-working-hours') return
|
// console.log('task clicked')
|
||||||
// console.log("task", task)
|
|
||||||
if (subtask.end.getTime() - subtask.start.getTime() <= 3600000) {
|
|
||||||
// console.log("ShortTask")
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
eventFocused(event) {
|
eventFocused(event) {
|
||||||
@@ -385,7 +382,7 @@ export default {
|
|||||||
padding: 20px 10px
|
padding: 20px 10px
|
||||||
|
|
||||||
.event-content
|
.event-content
|
||||||
&.blocker
|
&.is-blocker
|
||||||
*
|
*
|
||||||
color: #ffffff !important
|
color: #ffffff !important
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,15 @@ import moment from 'moment'
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
generateTimelineTasks(subtasks, date, employee) {
|
generateTimelineTasks(subtasks, date, employee) {
|
||||||
return [
|
const { tasks, blockers, homeoffices } = this.generateTimelineEvents(subtasks, employee, date)
|
||||||
...this.generateTimelineEvents(subtasks, employee, date),
|
const { nonWorkingHours } = this.generateTimelineNonWorkingHours(date, employee)
|
||||||
...this.generateTimelineNonWorkingHours(date, employee)
|
|
||||||
]
|
return {
|
||||||
|
tasks,
|
||||||
|
blockers,
|
||||||
|
nonWorkingHours,
|
||||||
|
homeoffices
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getUnscheduledTime(subtasks) {
|
getUnscheduledTime(subtasks) {
|
||||||
@@ -21,19 +26,24 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
generateTimelineEvents(subtasks, employee, date) {
|
generateTimelineEvents(subtasks, employee, date) {
|
||||||
let events = []
|
let blockers = []
|
||||||
|
const tasks = []
|
||||||
|
|
||||||
subtasks.forEach(subtask => {
|
subtasks.forEach(subtask => {
|
||||||
if (subtask.type == 'blocker') {
|
if (['blocker', 'adhoc', 'home_office', 'vacation', 'free_day'].includes(subtask.type)) {
|
||||||
events = [...events, ...this._generateEventsFromBlocker(subtask, date)]
|
blockers = [...blockers, ...this._generateEventsFromBlocker(subtask, date)]
|
||||||
} else {
|
} else {
|
||||||
subtask.timeblocks?.forEach((timeblock) => {
|
subtask.timeblocks?.forEach((timeblock) => {
|
||||||
events.push(this._composeTimelineEvent(subtask, employee, date, timeblock))
|
tasks.push(this._composeTimelineEvent(subtask, employee, date, timeblock))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return events
|
return {
|
||||||
|
tasks,
|
||||||
|
blockers: blockers.filter(blocker => blocker.type != 'home_office'),
|
||||||
|
homeoffices: blockers.filter(blocker => blocker.type == 'home_office')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_composeTimelineEvent(subtask, employee, date, timeblock) {
|
_composeTimelineEvent(subtask, employee, date, timeblock) {
|
||||||
@@ -50,7 +60,10 @@ export default {
|
|||||||
split: this._getSplitFromDate(date, timeblock.start),
|
split: this._getSplitFromDate(date, timeblock.start),
|
||||||
project_code: subtask.project_code,
|
project_code: subtask.project_code,
|
||||||
subtask: subtask,
|
subtask: subtask,
|
||||||
_timeblock_id: timeblock.id
|
type: 'subtask',
|
||||||
|
_timeblock_id: timeblock.id,
|
||||||
|
_real_start: new Date(timeblock.start),
|
||||||
|
_real_end: new Date(timeblock.end)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -58,8 +71,7 @@ export default {
|
|||||||
const start = moment(blocker.start)
|
const start = moment(blocker.start)
|
||||||
const end = moment(blocker.end)
|
const end = moment(blocker.end)
|
||||||
|
|
||||||
const dates = start == end ? [moment(start).format('YYYY-MM-DD')] : this._getDatesInRange(start, end)
|
const dates = start.isSame(end, 'date') ? [moment(start).format('YYYY-MM-DD')] : this._getDatesInRange(start, end)
|
||||||
|
|
||||||
const blockers = dates.map(d => {
|
const blockers = dates.map(d => {
|
||||||
const diffInDays = differenceInCalendarDays(date, new Date(d))
|
const diffInDays = differenceInCalendarDays(date, new Date(d))
|
||||||
const dStart = new Date(moment(d).set({hours: start.hours(), minutes: start.minutes()}).format('YYYY-MM-DD HH:mm'))
|
const dStart = new Date(moment(d).set({hours: start.hours(), minutes: start.minutes()}).format('YYYY-MM-DD HH:mm'))
|
||||||
@@ -71,10 +83,13 @@ export default {
|
|||||||
start: addDays(dStart, diffInDays),
|
start: addDays(dStart, diffInDays),
|
||||||
end: addDays(dEnd, diffInDays),
|
end: addDays(dEnd, diffInDays),
|
||||||
date: new Date(d),
|
date: new Date(d),
|
||||||
type: 'blocker',
|
type: blocker.type,
|
||||||
|
isBlocker: true,
|
||||||
initials: `${blocker.employee?.name[0]}${blocker.employee?.surname[0]}`,
|
initials: `${blocker.employee?.name[0]}${blocker.employee?.surname[0]}`,
|
||||||
color: '#B00020',
|
color: '#B00020',
|
||||||
draggable: false
|
draggable: false,
|
||||||
|
_real_start: dStart,
|
||||||
|
_real_end: dEnd
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -117,7 +132,7 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return events
|
return {nonWorkingHours: events}
|
||||||
},
|
},
|
||||||
|
|
||||||
_getSplitFromDate(date, start) {
|
_getSplitFromDate(date, start) {
|
||||||
@@ -125,8 +140,12 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_getDifferenceInHours(date1, date2) {
|
_getDifferenceInHours(date1, date2) {
|
||||||
let diff =(date1.getTime() - date2.getTime()) / 1000;
|
return this._getDifferenceInMinutes(date1, date2) / 60
|
||||||
diff /= (60 * 60)
|
},
|
||||||
|
|
||||||
|
_getDifferenceInMinutes(date1, date2) {
|
||||||
|
let diff = (date1.getTime() - date2.getTime()) / 1000
|
||||||
|
diff /= 60
|
||||||
return Math.abs(Math.round(diff))
|
return Math.abs(Math.round(diff))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -37,29 +37,77 @@ export default {
|
|||||||
|
|
||||||
splitDays() {
|
splitDays() {
|
||||||
const days = []
|
const days = []
|
||||||
const workingHours = {}
|
const homeoffice = {}
|
||||||
|
const schedulesCapacityBySplit = {}
|
||||||
|
|
||||||
|
const now = moment()
|
||||||
|
const dailyCapacityMinutes = this.user.work_end - this.user.work_start
|
||||||
|
|
||||||
this.timelineData.tasks.forEach(task => {
|
this.timelineData.tasks.forEach(task => {
|
||||||
if (!workingHours[task.split])
|
|
||||||
workingHours[task.split] = 0
|
|
||||||
|
|
||||||
if (task.type == 'non-working-hours' || task.subtask?.is_finished || task.blocker?.is_finished)
|
if (task.type == 'non-working-hours' || task.subtask?.is_finished || task.blocker?.is_finished)
|
||||||
return
|
return
|
||||||
|
|
||||||
workingHours[task.split] += timelineUtils._getDifferenceInHours(task.end, task.start)
|
if (!schedulesCapacityBySplit[task.split])
|
||||||
|
schedulesCapacityBySplit[task.split] = 0
|
||||||
|
|
||||||
|
if (now.isAfter(moment(task._real_end))) {
|
||||||
|
// Ignore elapsed task
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else if (now.isAfter(moment(task._real_start) && now.isBefore(moment(task._real_end)))) {
|
||||||
|
// Task in progress
|
||||||
|
schedulesCapacityBySplit[task.split] += timelineUtils._getDifferenceInMinutes(task._real_end, new Date())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Future task
|
||||||
|
schedulesCapacityBySplit[task.split] += timelineUtils._getDifferenceInMinutes(task._real_end, task._real_start)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
schedulesCapacityBySplit[1] = 0 // Set YESTERDAY value to 0
|
||||||
|
|
||||||
|
this.timelineData.homeoffices.forEach(task => {
|
||||||
|
homeoffice[task.split] = true
|
||||||
})
|
})
|
||||||
|
|
||||||
for (let i = 0; i < 7; i++) {
|
for (let i = 0; i < 7; i++) {
|
||||||
|
if (!schedulesCapacityBySplit[i + 1])
|
||||||
|
schedulesCapacityBySplit[i + 1] = 0
|
||||||
|
|
||||||
|
let unscheduledTime
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
// Yesterday
|
||||||
|
unscheduledTime = 0
|
||||||
|
} else if (i == 1) {
|
||||||
|
// Today
|
||||||
|
const elapsedMinutes = now.diff(now.clone().startOf('day'), 'minutes')
|
||||||
|
const workStart = this.user.work_start > elapsedMinutes ? this.user.workStart : elapsedMinutes
|
||||||
|
const todayCapacityMinutes = this.user.work_end - workStart
|
||||||
|
unscheduledTime = todayCapacityMinutes - schedulesCapacityBySplit[i + 1] < 0 ? 0 : todayCapacityMinutes - schedulesCapacityBySplit[i + 1]
|
||||||
|
} else {
|
||||||
|
// Future
|
||||||
|
unscheduledTime = dailyCapacityMinutes - schedulesCapacityBySplit[i + 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(unscheduledTime)
|
||||||
|
|
||||||
days.push({
|
days.push({
|
||||||
id: i + 1,
|
id: i + 1,
|
||||||
fullname: `${this.filter.employee.name} ${this.filter.employee.surname}`,
|
fullname: `${this.filter.employee.name} ${this.filter.employee.surname}`,
|
||||||
initials: this.filter.employee.name.charAt(0).toUpperCase() + this.filter.employee.surname.charAt(0).toUpperCase(),
|
initials: this.filter.employee.name.charAt(0).toUpperCase() + this.filter.employee.surname.charAt(0).toUpperCase(),
|
||||||
unscheduledTime: workingHours[i + 1],
|
unscheduledTime: (unscheduledTime / 60).toFixed(1),
|
||||||
date: addDays(this.filter.start, i),
|
date: addDays(this.filter.start, i),
|
||||||
|
isHomeoffice: homeoffice[i],
|
||||||
isWeekend: timelineUtils.isWeekend(addDays(this.filter.start, i))
|
isWeekend: timelineUtils.isWeekend(addDays(this.filter.start, i))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(days)
|
||||||
|
|
||||||
return days
|
return days
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -74,11 +122,14 @@ export default {
|
|||||||
if (!this.subtasks || !this.filter)
|
if (!this.subtasks || !this.filter)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
const { tasks, blockers, nonWorkingHours, homeoffices } = timelineUtils.generateTimelineTasks(this.subtasks, new Date(this.filter.start), this.filter.employee)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: this.filter.employee.name,
|
name: this.filter.employee.name,
|
||||||
surname: this.filter.employee.surname,
|
surname: this.filter.employee.surname,
|
||||||
unscheduledTime: this.unscheduledTime,
|
unscheduledTime: this.unscheduledTime,
|
||||||
tasks: timelineUtils.generateTimelineTasks(this.subtasks, new Date(this.filter.start), this.filter.employee)
|
tasks: [...tasks, ...blockers, ...nonWorkingHours],
|
||||||
|
homeoffices
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -121,9 +172,9 @@ export default {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { subtasks, blockers } = await this.$axios.get_auth(`v1/subtasks?${queryParameters}`)
|
const { subtasks, blockers } = await this.$axios.get_auth(`v1/subtasks?${queryParameters}`)
|
||||||
this.config.scrollHour = this.filter?.employee.work_start - 1
|
this.config.scrollHour = (this.filter?.employee.work_start / 60) - 1
|
||||||
this.config.date = this.filter.start
|
this.config.date = this.filter.start
|
||||||
this.subtasks = [...subtasks, ...blockers.map(blocker => ({...blocker, type: 'blocker'}))]
|
this.subtasks = [...subtasks, ...blockers]
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$toast.error('Nepodarilo sa nacitat data!')
|
this.$toast.error('Nepodarilo sa nacitat data!')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,8 @@ export default {
|
|||||||
|
|
||||||
_updateFilters() {
|
_updateFilters() {
|
||||||
this.filter.start = this.date
|
this.filter.start = this.date
|
||||||
this.filter.end = addDays(this.date, 1)
|
this.filter.end = this.date
|
||||||
|
// this.filter.end = addDays(this.date, 1)
|
||||||
this.selectedDate = String(this.filter.start?.toLocaleDateString('sk-SK'))
|
this.selectedDate = String(this.filter.start?.toLocaleDateString('sk-SK'))
|
||||||
|
|
||||||
this._emitFilterChanged()
|
this._emitFilterChanged()
|
||||||
|
|||||||
@@ -9,29 +9,44 @@ export default {
|
|||||||
if (!this.subtasks || !this.blockers)
|
if (!this.subtasks || !this.blockers)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
const blockers = this._generateBlockers()
|
||||||
|
|
||||||
|
console.log([...this._generateNonWorking(), ...this._generateTasks(), ...blockers.filter(blocker => blocker.type != 'home_office')])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
unscheduledTime: 333,
|
unscheduledTime: 333,
|
||||||
tasks: [...this._generateNonWorking(), ...this._generateTasks(), ...this._generateBlockers()]
|
tasks: [...this._generateNonWorking(), ...this._generateTasks(), ...blockers.filter(blocker => blocker.type != 'home_office')],
|
||||||
|
homeoffices: [...blockers.filter(blocker => blocker.type == 'home_office')]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
splitDays() {
|
splitDays() {
|
||||||
const days = []
|
const days = []
|
||||||
|
const homeoffice = {}
|
||||||
|
|
||||||
this.filter.team.employees.forEach((employee, index) => {
|
this.filter.team.employees.forEach((employee, index) => {
|
||||||
let workingHours = 0
|
let workingHours = 0
|
||||||
|
|
||||||
this.calendarData.tasks.forEach(task => {
|
this.calendarData.tasks.forEach(task => {
|
||||||
if (task?.subtask?.employee_id == employee.id)
|
if ((task.subtask?.employee?.id != employee.id) && (task.blocker?.employee?.id != employee.id))
|
||||||
|
return
|
||||||
|
|
||||||
workingHours += timelineUtils._getDifferenceInHours(task.end, task.start)
|
workingHours += timelineUtils._getDifferenceInHours(task.end, task.start)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.calendarData.homeoffices.forEach(task => {
|
||||||
|
if (task.blocker.employee?.id != employee.id) return
|
||||||
|
|
||||||
|
homeoffice[task.split] = true
|
||||||
|
})
|
||||||
|
|
||||||
days.push({
|
days.push({
|
||||||
id: index + 1,
|
id: index + 1,
|
||||||
name: employee.name,
|
name: employee.name,
|
||||||
fullname: `${employee.name} ${employee.surname}`,
|
fullname: `${employee.name} ${employee.surname}`,
|
||||||
initials: employee.name.charAt(0).toUpperCase() + employee.surname.charAt(0).toUpperCase(),
|
initials: employee.name.charAt(0).toUpperCase() + employee.surname.charAt(0).toUpperCase(),
|
||||||
unscheduledTime: workingHours
|
unscheduledTime: workingHours,
|
||||||
|
isHomeoffice: homeoffice[index + 1] ? true : false
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -43,14 +58,14 @@ export default {
|
|||||||
_generateNonWorking() {
|
_generateNonWorking() {
|
||||||
const nonWorkingHours = []
|
const nonWorkingHours = []
|
||||||
const date = new Date(this.filter.start)
|
const date = new Date(this.filter.start)
|
||||||
let earliestStartHour = null
|
let earliestStartMinutes = null
|
||||||
this.calendarConfig.date = date
|
this.calendarConfig.date = date
|
||||||
|
|
||||||
const { start: dayStart, end: dayEnd } = this._getDayStartEnd()
|
const { start: dayStart, end: dayEnd } = this._getDayStartEnd()
|
||||||
|
|
||||||
this.filter.team.employees.forEach((employee, index) => {
|
this.filter.team.employees.forEach((employee, index) => {
|
||||||
if (!earliestStartHour || employee.work_start < earliestStartHour)
|
if (!earliestStartMinutes || (employee.work_start) < earliestStartMinutes)
|
||||||
earliestStartHour = employee.work_start
|
earliestStartMinutes = employee.work_start
|
||||||
|
|
||||||
|
|
||||||
nonWorkingHours.push({
|
nonWorkingHours.push({
|
||||||
@@ -72,7 +87,7 @@ export default {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
this.calendarConfig.scrollHour = earliestStartHour - 1
|
this.calendarConfig.scrollHour = (earliestStartMinutes) - 1
|
||||||
return nonWorkingHours
|
return nonWorkingHours
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -107,7 +122,7 @@ export default {
|
|||||||
initials: employee?.name?.charAt(0)?.toUpperCase() + employee?.surname?.charAt(0)?.toUpperCase(),
|
initials: employee?.name?.charAt(0)?.toUpperCase() + employee?.surname?.charAt(0)?.toUpperCase(),
|
||||||
split: split,
|
split: split,
|
||||||
project_code: subtask.project_code,
|
project_code: subtask.project_code,
|
||||||
subtask: subtask,
|
subtask,
|
||||||
_timeblock_id: timeblock.id
|
_timeblock_id: timeblock.id
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -136,7 +151,8 @@ export default {
|
|||||||
split,
|
split,
|
||||||
start: new Date(blocker.start),
|
start: new Date(blocker.start),
|
||||||
end: new Date(blocker.end),
|
end: new Date(blocker.end),
|
||||||
type: 'blocker',
|
type: blocker.type,
|
||||||
|
isBlocker: true,
|
||||||
initials: `${employee?.name[0]}${employee?.surname[0]}`,
|
initials: `${employee?.name[0]}${employee?.surname[0]}`,
|
||||||
color: '#B00020',
|
color: '#B00020',
|
||||||
draggable: false,
|
draggable: false,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<A-team-filter v-if="$store.getters['tm/isInitialized']" :unscheduledTime="calendarData?.unscheduledTime || 0" @filter-changed="onFilterChanged" />
|
<A-team-filter v-if="$store.getters['tm/isInitialized']" :unscheduledTime="calendarData?.unscheduledTime || 0" @filter-changed="onFilterChanged" />
|
||||||
|
|
||||||
<Z-timeline v-if="calendarData" :cal-data="calendarData" :cal-config="calendarConfig" :splits="splitDays" />
|
<Z-timeline v-if="calendarData" :cal-data="calendarData" :cal-config="calendarConfig" :splits="splitDays" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-row no-gutters class="align-center" v-if="employee">
|
<v-row no-gutters class="align-center">
|
||||||
<v-col cols="5">
|
<v-col cols="5">
|
||||||
<v-sheet class="py-3">
|
<v-sheet class="py-3">
|
||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
@@ -12,9 +12,9 @@
|
|||||||
<v-col cols="7">
|
<v-col cols="7">
|
||||||
<v-sheet class="py-3 d-flex align-center">
|
<v-sheet class="py-3 d-flex align-center">
|
||||||
<p class="employee-selected-avatar d-flex justify-center align-center">
|
<p class="employee-selected-avatar d-flex justify-center align-center">
|
||||||
{{ employee._initials }}
|
{{ employee ? employee._initials : '?' }}
|
||||||
</p>
|
</p>
|
||||||
<p class="ml-2">{{ employee._fullName }}</p>
|
<p class="ml-2">{{ employee ? employee._fullName : $t('Unasigned') }}</p>
|
||||||
</v-sheet>
|
</v-sheet>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|||||||
@@ -3,34 +3,28 @@ export default {
|
|||||||
employeesOptions() {
|
employeesOptions() {
|
||||||
const selectedEmployees = [...this.mastertask.employees].map(employee => employee.id)
|
const selectedEmployees = [...this.mastertask.employees].map(employee => employee.id)
|
||||||
|
|
||||||
const employees = this.enrichedEmployees.filter(
|
return this.enrichedEmployees.filter(
|
||||||
(employee) => !selectedEmployees.includes(employee.id)
|
(employee) => !selectedEmployees.includes(employee.id)
|
||||||
) || []
|
) || []
|
||||||
|
},
|
||||||
|
|
||||||
return employees.map((employee) => {
|
projectsOptions() {
|
||||||
return {
|
// Added to "paginate" projects, because v-autocomplete was unable to handle so many projects at once
|
||||||
key: employee.id,
|
|
||||||
value: `${employee.name} ${employee.surname}`,
|
const projects = this.projects.filter(project => project.code.includes(this.projectCodeSearch))
|
||||||
}
|
return projects?.length ? projects.slice(0, 10) : this.projects.slice(0, 10)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onProjectSelected({ key }) {
|
// onProjectSelected(id) {
|
||||||
const project = this.projects.find(project => project.id == key)
|
// const project = this.projects.find(project => project.id == id)
|
||||||
this.mastertask.project_code = project.code
|
// this.mastertask.project_code = project.code
|
||||||
this.mastertask.project_id = project.id
|
// this.mastertask.project_id = project.id
|
||||||
},
|
// },
|
||||||
|
|
||||||
onMasterTaskSelected({ key }) {
|
onEmployeeSelected(id) {
|
||||||
const mastertask = this.mastertasks.find(mastertask => mastertask.id == key)
|
const employee = this.enrichedEmployees.find(employee => employee.id == id)
|
||||||
this.subtask.master_task = mastertask
|
|
||||||
this.subtask.project_code = mastertask.project_code
|
|
||||||
},
|
|
||||||
|
|
||||||
onEmployeeSelected({ key }) {
|
|
||||||
const employee = this.enrichedEmployees.find(employee => employee.id == key)
|
|
||||||
this.mastertask.employees.push(employee)
|
this.mastertask.employees.push(employee)
|
||||||
this.showAddEmployeeInput = false
|
this.showAddEmployeeInput = false
|
||||||
},
|
},
|
||||||
@@ -60,6 +54,6 @@ export default {
|
|||||||
|
|
||||||
this.mastertask.team = this.teams.find(team => team.id == value)
|
this.mastertask.team = this.teams.find(team => team.id == value)
|
||||||
this.mastertask.employees = this.mastertask.team.employees
|
this.mastertask.employees = this.mastertask.team.employees
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,17 +8,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-card-actions class="d-flex flex-column modal-content">
|
<v-card-actions class="d-flex flex-column modal-content">
|
||||||
<Z-autocomplete label="Kód projektu" :options="projects.map((project) => ({ key: project.id, value: project.code }))" :validations="v$.mastertask.project_code" :clear-on-submit="false" :value="mastertask.project_code" :class="{ error: v$.mastertask.project_code.$errors.length }" class="modal-input" @option-selected="onProjectSelected" />
|
<v-autocomplete v-model="mastertask.project_id" :label="$t('Project code')" :class="{error: v$.mastertask.project_id.$errors.length}" :items="projectsOptions" item-title="code" item-value="id" variant="solo" class="modal-input" clearable @update:search="projectCodeSearch = $event" />
|
||||||
|
|
||||||
<v-text-field v-model="mastertask.name" @focus="onInputFocus" class="modal-input" label="Názov mastertasku" variant="solo" :class="{ error: v$.mastertask.name.$errors.length }" :hint="v$.mastertask.name.$errors ? errorUtils.parseErrors(v$.mastertask.name.$errors) : null"></v-text-field>
|
<v-text-field v-model="mastertask.name" @focus="onInputFocus" class="modal-input" label="Názov mastertasku" variant="solo" :class="{ error: v$.mastertask.name.$errors.length }" :hint="v$.mastertask.name.$errors ? errorUtils.parseErrors(v$.mastertask.name.$errors) : null"></v-text-field>
|
||||||
|
|
||||||
<Datepicker v-model="mastertask.deadline" @focus="onDateFocus" class="modal-input" format="dd.MM.yyyy, HH:mm" locale="sk" :class="{ error: v$.mastertask.deadline.$errors.length }" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Deadline" />
|
<Datepicker v-model="mastertask.deadline" @focus="onDateFocus" :min-date="new Date()" class="modal-input" format="dd.MM.yyyy, HH:mm" locale="sk" :class="{ error: v$.mastertask.deadline.$errors.length }" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Deadline" />
|
||||||
|
|
||||||
<v-text-field v-model="mastertask.duration" @focus="onInputFocus" class="modal-input mt-5" variant="solo" type="number" disabled :label="`${mastertask.duration} h`"></v-text-field>
|
<v-text-field v-model="mastertask.duration" @focus="onInputFocus" class="modal-input mt-5" variant="solo" type="number" disabled :label="`${mastertask.duration} h`"></v-text-field>
|
||||||
|
|
||||||
<v-select v-model="this.mastertask.team_id" @focus="onInputFocus" class="modal-input border-select" :class="{ error: v$.mastertask.team_id.$errors.length }" label="Tím" variant="solo" :items="teams" item-value="id" item-title="name"></v-select>
|
<v-select v-model="mastertask.team_id" @focus="onInputFocus" class="modal-input border-select" :class="{ error: v$.mastertask.team_id.$errors.length }" label="Tím" variant="solo" :items="teams" item-value="id" item-title="name"></v-select>
|
||||||
|
|
||||||
<template v-if="!mastertask.id">
|
<template v-if="!mastertask.id && mastertask.team_id">
|
||||||
<v-text-field v-for="(employee, index) in mastertask.employees" :key="employee.id" @focus="onInputFocus" :class="{ error: !mastertask.employees[index].duration }" class="modal-input" :label="`${employee.name} ${employee.surname}`" variant="solo" placeholder="h" v-model="mastertask.employees[index].duration" type="number" min="1" @input="onEmployeeDurationChanged">
|
<v-text-field v-for="(employee, index) in mastertask.employees" :key="employee.id" @focus="onInputFocus" :class="{ error: !mastertask.employees[index].duration }" class="modal-input" :label="`${employee.name} ${employee.surname}`" variant="solo" placeholder="h" v-model="mastertask.employees[index].duration" type="number" min="1" @input="onEmployeeDurationChanged">
|
||||||
<p class="employee-select-avatar d-flex justify-center align-center">
|
<p class="employee-select-avatar d-flex justify-center align-center">
|
||||||
{{ employee.name.charAt(0) + employee.surname.charAt(0) }}
|
{{ employee.name.charAt(0) + employee.surname.charAt(0) }}
|
||||||
@@ -26,7 +26,9 @@
|
|||||||
</v-text-field>
|
</v-text-field>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<Z-autocomplete label="Vyhľadať zamestnanca" v-if="showAddEmployeeInput" :options="employeesOptions" class="modal-input" @option-selected="onEmployeeSelected" />
|
<v-autocomplete v-if="showAddEmployeeInput" :label="$t('Search for employee')" :class="{error: v$.mastertask.project_id.$errors.length}" :items="employeesOptions" item-title="_fullName" item-value="id" variant="solo" class="modal-input" clearable @update:model-value="onEmployeeSelected" />
|
||||||
|
|
||||||
|
<!-- <Z-autocomplete label="Vyhľadať zamestnanca" :options="employeesOptions" class="modal-input" @option-selected="onEmployeeSelected" /> -->
|
||||||
|
|
||||||
<v-btn class="w-100 mb-5 button secondary" :disabled="!mastertask.team?.id" @click="showAddEmployeeInput = true"> <v-icon class="mx-1" icon="mdi-plus" />Pridať zamestnanca </v-btn>
|
<v-btn class="w-100 mb-5 button secondary" :disabled="!mastertask.team?.id" @click="showAddEmployeeInput = true"> <v-icon class="mx-1" icon="mdi-plus" />Pridať zamestnanca </v-btn>
|
||||||
|
|
||||||
@@ -79,11 +81,11 @@ import ZFilesUpload from '@/plugins/tm@_components/z-files-upload.vue'
|
|||||||
import useVuelidate from '@vuelidate/core'
|
import useVuelidate from '@vuelidate/core'
|
||||||
import { required } from '@vuelidate/validators'
|
import { required } from '@vuelidate/validators'
|
||||||
import errorUtils from '@/plugins/lib@auth/_utils/error.utils'
|
import errorUtils from '@/plugins/lib@auth/_utils/error.utils'
|
||||||
import ZAutocomplete from '@/plugins/tm@_components/z-autocomplete.vue'
|
// import ZAutocomplete from '@/plugins/tm@_components/z-autocomplete.vue'
|
||||||
import VuetifyFixFocusMixin from '@/plugins/tm@modal/_mixins/vuetify-fix-focus'
|
import VuetifyFixFocusMixin from '@/plugins/tm@modal/_mixins/vuetify-fix-focus'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { QuillEditor } from '@vueup/vue-quill'
|
import { QuillEditor } from '@vueup/vue-quill'
|
||||||
import tmUtils from '@/plugins/tm@_utils/tm.utils'
|
// import tmUtils from '@/plugins/tm@_utils/tm.utils'
|
||||||
|
|
||||||
import '@vueup/vue-quill/dist/vue-quill.snow.css'
|
import '@vueup/vue-quill/dist/vue-quill.snow.css'
|
||||||
|
|
||||||
@@ -94,7 +96,7 @@ import { mapGetters } from 'vuex'
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
// MIXINS
|
// MIXINS
|
||||||
// computed: employeesOptions
|
// computed: employeesOptions, projectsOptions
|
||||||
// methods: onProjectSelected, onEmployeeSelected, onEmployeeDurationChanged
|
// methods: onProjectSelected, onEmployeeSelected, onEmployeeDurationChanged
|
||||||
// watch: mastertask.team_id
|
// watch: mastertask.team_id
|
||||||
|
|
||||||
@@ -106,7 +108,7 @@ export default {
|
|||||||
ATasksTable,
|
ATasksTable,
|
||||||
Datepicker,
|
Datepicker,
|
||||||
ZFilesUpload,
|
ZFilesUpload,
|
||||||
ZAutocomplete,
|
// ZAutocomplete,
|
||||||
QuillEditor
|
QuillEditor
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -119,6 +121,7 @@ export default {
|
|||||||
mastertask: null,
|
mastertask: null,
|
||||||
showAddEmployeeInput: false,
|
showAddEmployeeInput: false,
|
||||||
date: null,
|
date: null,
|
||||||
|
projectCodeSearch: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -127,13 +130,29 @@ export default {
|
|||||||
'teams',
|
'teams',
|
||||||
'projects',
|
'projects',
|
||||||
'enrichedEmployees'
|
'enrichedEmployees'
|
||||||
])
|
]),
|
||||||
|
|
||||||
|
|
||||||
|
enrichedSubtasks() {
|
||||||
|
if (!this.mastertask?.subtasks)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return this.mastertask.subtasks.map(subtask => {
|
||||||
|
const employee = this.enrichedEmployees.find(employee => employee.id == subtask.employee_id)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...subtask,
|
||||||
|
_initials: employee ? employee.name.charAt(0) + employee.surname.charAt(0) : '?',
|
||||||
|
_fullName: employee ? `${employee.name} ${employee.surname}` : ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
validations() {
|
validations() {
|
||||||
return {
|
return {
|
||||||
mastertask: {
|
mastertask: {
|
||||||
project_code: { required },
|
project_id: { required },
|
||||||
team_id: { required },
|
team_id: { required },
|
||||||
name: { required },
|
name: { required },
|
||||||
description: { required },
|
description: { required },
|
||||||
@@ -171,6 +190,7 @@ export default {
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async showModal({mastertask, editMode = false}) {
|
async showModal({mastertask, editMode = false}) {
|
||||||
|
this.editMode = null
|
||||||
this.visible = true
|
this.visible = true
|
||||||
this.mastertask = null
|
this.mastertask = null
|
||||||
this.$nextTick(() => this.v$.$reset())
|
this.$nextTick(() => this.v$.$reset())
|
||||||
@@ -179,11 +199,12 @@ export default {
|
|||||||
if (mastertask?.id) {
|
if (mastertask?.id) {
|
||||||
this.mastertask = await this.$axios.get_auth_data(`v1/mastertasks/${mastertask.id}`)
|
this.mastertask = await this.$axios.get_auth_data(`v1/mastertasks/${mastertask.id}`)
|
||||||
|
|
||||||
const project = this.projects.find((project) => project.code == this.mastertask?.project_code)
|
// TODO zmazat ked zacne prichadzat project_id a team_id
|
||||||
|
const project = this.projects.find((project) => project.code == this.mastertask.project_code)
|
||||||
this.mastertask.team_id = this.mastertask.team?.id || null
|
|
||||||
this.mastertask.project_id = project.id
|
this.mastertask.project_id = project.id
|
||||||
this.mastertask.project_code = project.code
|
this.mastertask.team_id = this.mastertask.team?.id || null
|
||||||
|
|
||||||
|
// this.mastertask.project_code = project.code
|
||||||
} else {
|
} else {
|
||||||
this.mastertask = { employees: [], duration: 0 }
|
this.mastertask = { employees: [], duration: 0 }
|
||||||
}
|
}
|
||||||
@@ -205,15 +226,6 @@ export default {
|
|||||||
if (this.$refs['description'])
|
if (this.$refs['description'])
|
||||||
this.mastertask.description = this.$refs['description'].getHTML()
|
this.mastertask.description = this.$refs['description'].getHTML()
|
||||||
|
|
||||||
// this.mastertask.subtasks = this.mastertask.subtasks.map(subtask => {
|
|
||||||
// const employee = this.mastertask.employees.find(employee => employee.id == subtask.employee_id)
|
|
||||||
// subtask.duration = employee.duration
|
|
||||||
|
|
||||||
// return subtask
|
|
||||||
// })
|
|
||||||
|
|
||||||
// this.mastertask.project_code = null
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.mastertask.deadline = moment(this.mastertask.deadline).format('YYYY-MM-DD HH:MM:SS')
|
this.mastertask.deadline = moment(this.mastertask.deadline).format('YYYY-MM-DD HH:MM:SS')
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<A-mastertask-name :name="subtask.master_task?.name || task.master_task" :id="subtask.master_task.id" :color="subtask.master_task.color" @close-modal="$emit('close-modal')" />
|
<A-mastertask-name :name="subtask._master_task.name" :id="subtask.master_task_id" :color="subtask._master_task.color" @close-modal="$emit('close-modal')" />
|
||||||
<A-mastertask-status :status="subtask.is_finished" />
|
<A-mastertask-status :status="subtask.is_finished" />
|
||||||
<A-task-timeblocks :timeblocks="subtask.timeblocks" :subtask="subtask" />
|
<A-task-timeblocks :timeblocks="subtask.timeblocks" :subtask="subtask" />
|
||||||
<Z-created-by :employee-id="subtask.created_by" />
|
<Z-created-by :employee-id="subtask.created_by" />
|
||||||
<A-task-assigned-employee :employee="subtask.employee" />
|
<A-task-assigned-employee :employee="subtask._employee" />
|
||||||
<A-task-planned-time :hours="subtask.duration" />
|
<A-task-planned-time :hours="subtask.duration" />
|
||||||
<A-task-remaining-time :hours="subtask.duration - subtask.spent_time" />
|
<A-task-remaining-time :hours="subtask.duration - subtask.spent_time" />
|
||||||
<A-task-spent-time :hours="subtask.spent_time" :subtask="subtask" />
|
<A-task-spent-time :hours="subtask.spent_time" :subtask="subtask" />
|
||||||
|
|||||||
@@ -10,9 +10,10 @@
|
|||||||
<v-card-actions class="d-flex flex-column modal-content">
|
<v-card-actions class="d-flex flex-column modal-content">
|
||||||
<v-text-field v-model="subtask.project_code" label="Kód projektu" :value="subtask.project_code" @focus="onInputFocus" class="modal-input" variant="solo" disabled></v-text-field>
|
<v-text-field v-model="subtask.project_code" label="Kód projektu" :value="subtask.project_code" @focus="onInputFocus" class="modal-input" variant="solo" disabled></v-text-field>
|
||||||
|
|
||||||
<Z-autocomplete label="Master task" :options="mastertasks.map((mastertask) => ({ key: mastertask.id, value: mastertask.name }))" :validations="v$.subtask.master_task.id" :clear-on-submit="false" :value="subtask?.master_task?.name" :class="{ error: v$.subtask.master_task.id.$errors.length }" class="modal-input" @option-selected="onMasterTaskSelected" />
|
<v-autocomplete v-model="subtask.master_task_id" label="Master task" :class="{error: v$.subtask.master_task_id.$errors.length}" :items="mastertasks" item-title="name" item-value="id" variant="solo" class="modal-input" clearable />
|
||||||
|
|
||||||
|
<v-autocomplete v-model="subtask.employee_id" label="Priradený" :class="{error: v$.subtask.employee_id.$errors.length}" :items="enrichedEmployees" item-title="_fullName" item-value="id" variant="solo" class="modal-input" clearable />
|
||||||
|
|
||||||
<Z-autocomplete label="Priradený" :value="subtask?.employee ? `${subtask?.employee?.name} ${subtask?.employee?.surname}` : ''" :options="enrichedEmployees.map(employee => ({key: employee.id, value: employee._fullName}))" :clear-on-submit="false" :class="{ error: v$.subtask.employee.$errors.length }" class="modal-input" @option-selected="onEmployeeSelected" />
|
|
||||||
<v-text-field v-model="subtask.duration" @focus="onInputFocus" class="modal-input" variant="solo" type="number" label="Časový odhad" :class="{ error: v$.subtask.duration.$errors.length }" :hint="v$.subtask.duration.$errors ? errorUtils.parseErrors(v$.subtask.duration.$errors) : null" append-inner-icon="mdi-clock-outline"></v-text-field>
|
<v-text-field v-model="subtask.duration" @focus="onInputFocus" class="modal-input" variant="solo" type="number" label="Časový odhad" :class="{ error: v$.subtask.duration.$errors.length }" :hint="v$.subtask.duration.$errors ? errorUtils.parseErrors(v$.subtask.duration.$errors) : null" append-inner-icon="mdi-clock-outline"></v-text-field>
|
||||||
|
|
||||||
<div class="w-100 modal-input">
|
<div class="w-100 modal-input">
|
||||||
@@ -28,8 +29,8 @@
|
|||||||
<v-card v-else height="100%" class="d-flex flex-column scrolling">
|
<v-card v-else height="100%" class="d-flex flex-column scrolling">
|
||||||
<div class="d-flex justify-space-between align-center">
|
<div class="d-flex justify-space-between align-center">
|
||||||
<div>
|
<div>
|
||||||
<p>{{ subtask.master_task?.project_code }}</p>
|
<p>{{ subtask._master_task.project_code }}</p>
|
||||||
<h1>{{ subtask.master_task?.name }}</h1>
|
<h1>{{ subtask._master_task.name }}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-icon @click.stop="closeModal()" icon="mdi-close" size="large" class="pb-5"></v-icon>
|
<v-icon @click.stop="closeModal()" icon="mdi-close" size="large" class="pb-5"></v-icon>
|
||||||
@@ -83,7 +84,7 @@ export default {
|
|||||||
ZTaskReadonlyInfo,
|
ZTaskReadonlyInfo,
|
||||||
ZFilesUpload,
|
ZFilesUpload,
|
||||||
QuillEditor,
|
QuillEditor,
|
||||||
ZAutocomplete
|
// ZAutocomplete
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
@@ -95,7 +96,6 @@ export default {
|
|||||||
errorUtils,
|
errorUtils,
|
||||||
v$: useVuelidate(),
|
v$: useVuelidate(),
|
||||||
preventInputFocus: false,
|
preventInputFocus: false,
|
||||||
mastertaskIdSelect: null,
|
|
||||||
showDatePicker: false,
|
showDatePicker: false,
|
||||||
selectedNewDate: []
|
selectedNewDate: []
|
||||||
}
|
}
|
||||||
@@ -105,24 +105,15 @@ export default {
|
|||||||
...mapGetters('tm', [
|
...mapGetters('tm', [
|
||||||
'mastertasks',
|
'mastertasks',
|
||||||
'enrichedEmployees'
|
'enrichedEmployees'
|
||||||
]),
|
])
|
||||||
|
|
||||||
filteredEmployees() {
|
|
||||||
if (!this.enrichedEmployees || !this.subtask?.master_task) return []
|
|
||||||
|
|
||||||
const selectedEmployees = this.subtask.master_task.employees?.map((employee) => employee.id) || []
|
|
||||||
return this.enrichedEmployees.filter((employee) => !selectedEmployees.includes(employee.id))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
validations() {
|
validations() {
|
||||||
return {
|
return {
|
||||||
subtask: {
|
subtask: {
|
||||||
master_task: {
|
master_task_id: { required },
|
||||||
id: { required }
|
|
||||||
},
|
|
||||||
duration: { required },
|
duration: { required },
|
||||||
employee: { required }
|
employee_id: { required }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -153,7 +144,6 @@ export default {
|
|||||||
this.subtask = this._enrichTask(data)
|
this.subtask = this._enrichTask(data)
|
||||||
} else {
|
} else {
|
||||||
this.subtask = { master_task: mastertask, timeblocks: [{start: tmUtils.formatDateTimeForBackend(moment()), end: tmUtils.formatDateTimeForBackend(moment())}] }
|
this.subtask = { master_task: mastertask, timeblocks: [{start: tmUtils.formatDateTimeForBackend(moment()), end: tmUtils.formatDateTimeForBackend(moment())}] }
|
||||||
this.mastertaskIdSelect = mastertask.id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.editMode = editMode || !this.subtask.id
|
this.editMode = editMode || !this.subtask.id
|
||||||
@@ -178,7 +168,7 @@ export default {
|
|||||||
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${this.subtask.id}`, this.subtask)
|
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${this.subtask.id}`, this.subtask)
|
||||||
this.$store.commit('tm/update_subtask', subtask)
|
this.$store.commit('tm/update_subtask', subtask)
|
||||||
} else {
|
} else {
|
||||||
const { subtask } = await this.$axios.post_auth(`v1/mastertasks/${this.subtask.master_task.id}/subtasks`, this.subtask)
|
const { subtask } = await this.$axios.post_auth(`v1/mastertasks/${this.subtask.master_task_id}/subtasks`, this.subtask)
|
||||||
this.subtask.id = subtask.id
|
this.subtask.id = subtask.id
|
||||||
this.$store.commit('tm/update_subtask', subtask)
|
this.$store.commit('tm/update_subtask', subtask)
|
||||||
}
|
}
|
||||||
@@ -190,17 +180,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async addNewDate() {
|
|
||||||
if (this.selectedNewDate) {
|
|
||||||
this.subtask.timeblocks.push({
|
|
||||||
start: this.selectedNewDate[0],
|
|
||||||
end: this.selectedNewDate[1]
|
|
||||||
})
|
|
||||||
this.showDatePicker = false
|
|
||||||
this.selectedNewDate = []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async downloadFile(id) {
|
async downloadFile(id) {
|
||||||
try {
|
try {
|
||||||
const file = await this.$axios.get_auth_data(`v1/subtasks/${this.subtask.id}`, { responseType: "arraybuffer" })
|
const file = await this.$axios.get_auth_data(`v1/subtasks/${this.subtask.id}`, { responseType: "arraybuffer" })
|
||||||
@@ -210,10 +189,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
removeDate(index) {
|
|
||||||
this.subtask.timeblocks.splice(index, 1)
|
|
||||||
},
|
|
||||||
|
|
||||||
openDeleteTaskModal(subtask) {
|
openDeleteTaskModal(subtask) {
|
||||||
this.$events.emit("show-delete-task-modal", { subtask })
|
this.$events.emit("show-delete-task-modal", { subtask })
|
||||||
},
|
},
|
||||||
@@ -226,35 +201,27 @@ export default {
|
|||||||
this.subtask.files = files
|
this.subtask.files = files
|
||||||
},
|
},
|
||||||
|
|
||||||
onEmployeeSelected({ key }) {
|
|
||||||
this.subtask.employee_id = key
|
|
||||||
},
|
|
||||||
|
|
||||||
_enrichTask(subtask) {
|
_enrichTask(subtask) {
|
||||||
subtask.master_task = this.mastertasks.find((mastertask) => mastertask.id == subtask.master_task_id)
|
return {
|
||||||
subtask.employee = this.enrichedEmployees.find((employee) => employee.id == subtask.employee_id)
|
...subtask,
|
||||||
subtask._created_by = this.enrichedEmployees.find((employee) => employee.id == subtask.created_by)
|
_created_by: this.enrichedEmployees.find((employee) => employee.id == subtask.created_by),
|
||||||
this.mastertaskIdSelect = subtask.master_task?.id
|
_employee: this.enrichedEmployees.find((employee) => employee.id == subtask.employee_id),
|
||||||
|
_master_task: this.mastertasks.find((mastertask) => mastertask.id == subtask.master_task_id)
|
||||||
return subtask
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
mastertaskIdSelect(value) {
|
'subtask.employee_id'(value, oldValue) {
|
||||||
if (!value || !this.subtask) return
|
if (!value || !oldValue) return
|
||||||
|
|
||||||
this.subtask.master_task = this.mastertasks.find((mastertask) => mastertask.id == value)
|
this.subtask.timeblocks = []
|
||||||
this.subtask.project_code = this.subtask.master_task.project_code
|
this.subtask._employee = this.enrichedEmployees.find((employee) => employee.id == this.subtask.employee_id)
|
||||||
},
|
},
|
||||||
|
|
||||||
"subtask.employee_id"(value, oldValue) {
|
'subtask.master_task_id'(value) {
|
||||||
if (!value) return
|
if (!value) return
|
||||||
|
this.subtask._master_task = this.mastertasks.find((mastertask) => mastertask.id == this.subtask.master_task_id)
|
||||||
if (value && oldValue)
|
|
||||||
this.subtask.timeblocks = []
|
|
||||||
|
|
||||||
this.subtask.employee = this.enrichedEmployees.find((employee) => employee.id == value)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
editMode() {
|
editMode() {
|
||||||
|
|||||||
@@ -1,59 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-dialog v-model="visible" max-width="750" max-height="90%" height="700px">
|
<v-dialog v-model="visible" max-width="750" max-height="90%" height="700px">
|
||||||
<W-loadable :content="team && allEmployees" class="h-100">
|
<W-loadable :content="team" class="h-100">
|
||||||
<v-card height="100%" class="d-flex flex-column">
|
<v-card height="100%" class="d-flex flex-column">
|
||||||
<div class="d-flex justify-space-between align-center modal-header">
|
<div class="d-flex justify-space-between align-center modal-header">
|
||||||
<h1>{{ team.id ? 'Upraviť tím' : 'Vytvoriť tím' }}</h1>
|
<h1>{{ team.id ? 'Upraviť tím' : 'Vytvoriť tím' }}</h1>
|
||||||
<v-icon
|
<v-icon @click.stop="closeModal()" icon="mdi-close" size="large"></v-icon>
|
||||||
@click.stop="closeModal()"
|
|
||||||
icon="mdi-close"
|
|
||||||
size="large"
|
|
||||||
></v-icon>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-card-actions class="d-flex flex-column modal-content">
|
<v-card-actions class="d-flex flex-column modal-content">
|
||||||
<v-text-field
|
<v-text-field class="modal-input" label="Názov tímu" variant="solo"
|
||||||
class="modal-input"
|
:class="{ error: v$.team.name.$errors.length }" :hint="
|
||||||
label="Názov tímu"
|
|
||||||
variant="solo"
|
|
||||||
:class="{ error: v$.team.name.$errors.length }"
|
|
||||||
:hint="
|
|
||||||
v$.team.name.$errors
|
v$.team.name.$errors
|
||||||
? errorUtils.parseErrors(v$.team.name.$errors)
|
? errorUtils.parseErrors(v$.team.name.$errors)
|
||||||
: null
|
: null
|
||||||
"
|
" v-model="team.name"></v-text-field>
|
||||||
v-model="team.name"
|
|
||||||
></v-text-field>
|
|
||||||
|
|
||||||
<div
|
<div class="relative w-100" v-for="(employee, index) in team.employees" :key="employee.id">
|
||||||
class="relative w-100"
|
<v-text-field class="modal-input" disabled label="Zamestanec" variant="solo"
|
||||||
v-for="(employee, index) in team.employees"
|
v-model="team.employees[index]._fullName">
|
||||||
:key="employee.id"
|
|
||||||
>
|
|
||||||
<v-text-field
|
|
||||||
class="modal-input"
|
|
||||||
disabled
|
|
||||||
label="Zamestanec"
|
|
||||||
variant="solo"
|
|
||||||
v-model="team.employees[index]._fullName"
|
|
||||||
>
|
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
|
|
||||||
<v-icon
|
<v-icon class="remove-input" @click.stop="team.employees.splice(index, 1)" icon="mdi-close"
|
||||||
class="remove-input"
|
size="small"></v-icon>
|
||||||
@click.stop="team.employees.splice(index, 1)"
|
|
||||||
icon="mdi-close"
|
|
||||||
size="small"
|
|
||||||
></v-icon>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Z-autocomplete
|
<v-autocomplete v-model="employeeSelect" label="Priradený"
|
||||||
label="Vyhľadať zamestnanca"
|
:class="{ error: v$.team.employees.$errors.length }" :items="employeesOptions"
|
||||||
:options="employeesOptions"
|
item-title="_fullName" item-value="id" variant="solo" class="modal-input" clearable
|
||||||
:validations="v$.team.employees"
|
ref="autocomplete" />
|
||||||
class="modal-input"
|
|
||||||
@option-selected="employeeSelected"
|
|
||||||
/>
|
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
|
|
||||||
<v-btn class="button primary block" @click="save()">{{ team.id ? 'UPRAVIŤ' : 'VYTVORIŤ' }}</v-btn>
|
<v-btn class="button primary block" @click="save()">{{ team.id ? 'UPRAVIŤ' : 'VYTVORIŤ' }}</v-btn>
|
||||||
@@ -63,31 +37,41 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ZAutocomplete from '@/plugins/tm@_components/z-autocomplete.vue'
|
|
||||||
import useVuelidate from '@vuelidate/core'
|
import useVuelidate from '@vuelidate/core'
|
||||||
import { required } from '@vuelidate/validators'
|
import { required } from '@vuelidate/validators'
|
||||||
import errorUtils from '@/plugins/lib@auth/_utils/error.utils'
|
import errorUtils from '@/plugins/lib@auth/_utils/error.utils'
|
||||||
import tmUtils from '@/plugins/tm@_utils/tm.utils'
|
import tmUtils from '@/plugins/tm@_utils/tm.utils'
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
const atLeastOne = (value) => value.length
|
const atLeastOne = (value) => value.length
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
emits: ['close', 'update'],
|
emits: ['close', 'update'],
|
||||||
|
|
||||||
components: {
|
|
||||||
ZAutocomplete,
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
visible: false,
|
visible: false,
|
||||||
allEmployees: null,
|
|
||||||
v$: useVuelidate(),
|
v$: useVuelidate(),
|
||||||
errorUtils,
|
errorUtils,
|
||||||
|
employeeSelect: null,
|
||||||
team: null
|
team: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters('tm', [
|
||||||
|
'enrichedEmployees'
|
||||||
|
]),
|
||||||
|
|
||||||
|
employeesOptions() {
|
||||||
|
const selectedEmployeesIds = this.team.employees.map(
|
||||||
|
(employee) => employee.id
|
||||||
|
)
|
||||||
|
|
||||||
|
return this.enrichedEmployees.filter(employee => !selectedEmployeesIds.includes(employee.id))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
validations() {
|
validations() {
|
||||||
return {
|
return {
|
||||||
team: {
|
team: {
|
||||||
@@ -104,9 +88,6 @@ export default {
|
|||||||
this.$nextTick(() => this.v$.$reset())
|
this.$nextTick(() => this.v$.$reset())
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const allEmployees = await this.$axios.get_auth_data('v1/employees')
|
|
||||||
this.allEmployees = tmUtils.enrichEmployees(allEmployees)
|
|
||||||
|
|
||||||
if (team?.id) {
|
if (team?.id) {
|
||||||
const t = await this.$axios.get_auth_data(`v1/teams/${team.id}`)
|
const t = await this.$axios.get_auth_data(`v1/teams/${team.id}`)
|
||||||
this.team = this._enrichTeam(t)
|
this.team = this._enrichTeam(t)
|
||||||
@@ -141,33 +122,21 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
employeeSelected(selectedOption) {
|
|
||||||
const employee = this.allEmployees.find((empl) => empl.id == selectedOption.key)
|
|
||||||
this.team.employees.push(employee)
|
|
||||||
},
|
|
||||||
|
|
||||||
_enrichTeam(team) {
|
_enrichTeam(team) {
|
||||||
team.employees = tmUtils.enrichEmployees(team.employees)
|
team.employees = tmUtils.enrichEmployees(team.employees)
|
||||||
return team
|
return team
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
watch: {
|
||||||
employeesOptions() {
|
employeeSelect(employeeId) {
|
||||||
const selectedEmployeesIds = this.team.employees.map(
|
if (!employeeId)
|
||||||
(employee) => employee.id
|
return
|
||||||
)
|
|
||||||
|
|
||||||
const employees = this.allEmployees.filter(
|
const employee = this.enrichedEmployees.find(employee => employee.id == employeeId)
|
||||||
(employee) => !selectedEmployeesIds.includes(employee.id)
|
this.team.employees.push(employee)
|
||||||
)
|
this.employeeSelect = null
|
||||||
|
this.$refs.autocomplete.search = ''
|
||||||
return employees.map((employee) => {
|
|
||||||
return {
|
|
||||||
key: employee.id,
|
|
||||||
value: `${employee.name} ${employee.surname}`,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user