mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 14:29:34 +00:00
Merged development/change-requests into main
This commit is contained in:
commit
86f27b73bf
12 files changed
+307
-49
No files matched your search
@@ -17,6 +17,7 @@
|
||||
<Z-blocker-modal ref="z-blocker-modal" />
|
||||
|
||||
<Z-master-task-modal ref="z-master-task-modal" @master-task-edited="onMasterTaskEdited" />
|
||||
<Z-delete-team-member-modal ref="z-delete-team-member-modal" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -30,6 +31,7 @@ import ZTaskAddTimeModal from '@/plugins/tm@modal/task/z-task-add-time-modal.v
|
||||
import ZBlockerModal from '@/plugins/tm@modal/blocker/z-blocker-modal.vue'
|
||||
import ZDeleteMasterTaskModal from '@/plugins/tm@modal/master-task/z-delete-master-task-modal.vue'
|
||||
import ZMasterTaskModal from '@/plugins/tm@modal/master-task/z-master-task-modal.vue'
|
||||
import ZDeleteTeamMemberModal from '@/plugins/tm@modal/master-task/z-delete-team-member-modal.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -42,7 +44,8 @@ export default {
|
||||
ZCompleteTaskModal,
|
||||
ZTaskAddTimeModal,
|
||||
ZBlockerModal,
|
||||
ZDeleteMasterTaskModal
|
||||
ZDeleteMasterTaskModal,
|
||||
ZDeleteTeamMemberModal
|
||||
},
|
||||
|
||||
mounted() {
|
||||
@@ -66,6 +69,10 @@ export default {
|
||||
this.$refs['z-delete-master-task-modal'].showModal({mastertask})
|
||||
})
|
||||
|
||||
this.$events.on('show-delete-team-member-modal', ({member, team}) => {
|
||||
this.$refs['z-delete-team-member-modal'].showModal({member, team})
|
||||
})
|
||||
|
||||
this.$events.on('show-subtask-modal', ({subtask, editMode, mastertask}) => {
|
||||
if(subtask && subtask.id) {
|
||||
const id = subtask.id
|
||||
|
||||
@@ -30,3 +30,14 @@
|
||||
|
||||
.relative
|
||||
position: relative !important
|
||||
|
||||
.splitted-inputs
|
||||
width: 100%
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
|
||||
.left
|
||||
width: 70% !important
|
||||
|
||||
.right
|
||||
width: 25% !important
|
||||
@@ -103,4 +103,4 @@ input[type="time"]::-webkit-calendar-picker-indicator
|
||||
|
||||
.v-row.subheader
|
||||
.v-input
|
||||
height: 56px !important
|
||||
height: 40px !important
|
||||
@@ -17,7 +17,7 @@ transition-group.vuecal__cell(
|
||||
@keypress.enter="onCellkeyPressEnter($event)"
|
||||
@touchstart="!isDisabled && onCellTouchStart($event, splitsCount ? split.id : null)"
|
||||
@mousedown="!isDisabled && onCellMouseDown($event, splitsCount ? split.id : null)"
|
||||
@click="!isDisabled && onCellClick($event)"
|
||||
@click="!isDisabled && onCellClick($event, split)"
|
||||
@dblclick="!isDisabled && onCellDblClick($event)"
|
||||
@contextmenu="!isDisabled && options.cellContextmenu && onCellContextMenu($event)"
|
||||
@dragenter="!isDisabled && editEvents.drag && dnd && dnd.cellDragEnter($event, $data, data.startDate)"
|
||||
@@ -63,6 +63,7 @@ transition-group.vuecal__cell(
|
||||
|
||||
<script>
|
||||
import Event from './event.vue'
|
||||
import tmUtils from '@/plugins/tm@_utils/tm.utils'
|
||||
|
||||
export default {
|
||||
inject: ['vuecal', 'utils', 'modules', 'view', 'domEvents'],
|
||||
@@ -80,6 +81,7 @@ export default {
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
tmUtils,
|
||||
cellOverlaps: {},
|
||||
cellOverlapsStreak: 1, // Largest amount of simultaneous events in cell.
|
||||
// On mouse down, save the time at cursor so it can be reused on cell focus event
|
||||
@@ -251,7 +253,22 @@ export default {
|
||||
this.onCellMouseDown(DOMEvent, split, true)
|
||||
},
|
||||
|
||||
onCellClick (DOMEvent) {
|
||||
onCellClick(DOMEvent, split) {
|
||||
if (DOMEvent.offsetY > 950 && DOMEvent.offsetY < 1700) {
|
||||
const dateFrom = split.date
|
||||
dateFrom.setHours(Math.floor(DOMEvent.offsetY / 100), 0, 0, 0)
|
||||
const dateTo = new Date(dateFrom)
|
||||
dateTo.setHours(dateFrom.getHours() + 1)
|
||||
this.$events.emit('show-subtask-modal', {})
|
||||
setTimeout(() => {
|
||||
this.$events.emit('add-timeblock', {
|
||||
id: null,
|
||||
start: tmUtils.formatDateTimeForBackend(dateFrom),
|
||||
end: tmUtils.formatDateTimeForBackend(dateTo)
|
||||
})
|
||||
}, 150)
|
||||
}
|
||||
|
||||
if (!this.isDOMElementAnEvent(DOMEvent.target)) this.selectCell(DOMEvent)
|
||||
},
|
||||
|
||||
|
||||
@@ -245,7 +245,6 @@ export default {
|
||||
);
|
||||
|
||||
const height = Math.max(bottom - top, 5); // Min height is 5px.
|
||||
|
||||
return { top, height };
|
||||
},
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
:scroll-to-hour="calConfig.scrollHour"
|
||||
:split-days="splits"
|
||||
:sticky-split-labels="true"
|
||||
:min-split-width="270"
|
||||
:min-split-width="220"
|
||||
@ready="onReady()"
|
||||
@view-change="weekChanged"
|
||||
@event-drop="eventMoved"
|
||||
@@ -304,11 +304,11 @@ export default {
|
||||
|
||||
// TIME COLUMN
|
||||
.vuecal__time-column
|
||||
width: 150px
|
||||
width: 80px
|
||||
box-shadow: none !important
|
||||
|
||||
.time-column-line
|
||||
width: 40px
|
||||
width: 20px
|
||||
height: 0
|
||||
border: 1px solid rgba(33, 33, 33, 0.08)
|
||||
margin-left: 10px
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<v-row class="px-10 py-8 subheader">
|
||||
<v-row class="px-7 py-5 subheader">
|
||||
<v-autocomplete
|
||||
v-model="selectedEmployee"
|
||||
class="subheader-input"
|
||||
@@ -120,8 +120,8 @@ export default {
|
||||
|
||||
.subheader-icon-button
|
||||
border: 1px solid #ABABAB
|
||||
height: 56px
|
||||
width: 56px
|
||||
height: 60px
|
||||
width: 60px
|
||||
min-width: auto !important
|
||||
padding: 0
|
||||
margin: 0
|
||||
@@ -136,9 +136,19 @@ export default {
|
||||
margin: 0
|
||||
|
||||
.subheader-input
|
||||
max-width: 175px
|
||||
min-width: 175px
|
||||
height: 60px !important
|
||||
|
||||
&:nth-child(2)
|
||||
max-width: 250px !important
|
||||
min-width: 250px
|
||||
height: 56px
|
||||
min-width: 250px !important
|
||||
|
||||
&:deep(.v-input__control)
|
||||
.v-field
|
||||
height: 60px !important
|
||||
--v-input-control-height: 60px !important
|
||||
--v-input-padding-top: 19px !important
|
||||
|
||||
&:deep(.v-input__details)
|
||||
display: none
|
||||
|
||||
@@ -33,6 +33,7 @@ export default {
|
||||
|
||||
onEmployeeSelected(id) {
|
||||
const employee = this.enrichedEmployees.find(employee => employee.id == id)
|
||||
console.log('add employee', employee)
|
||||
this.mastertask.employees.push(employee)
|
||||
this.showAddEmployeeInput = false
|
||||
},
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<v-dialog v-model="visible" max-width="500" >
|
||||
<v-card>
|
||||
<h1 class="text-h5">
|
||||
Chcete túto osobu odstrániť z tímu?
|
||||
</h1>
|
||||
<v-card-text>{{ member.name + ' ' + member.surname }} bude odstránený/á z teamu.</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn
|
||||
class="button secondary"
|
||||
variant="text"
|
||||
@click="closeModal()"
|
||||
>
|
||||
Zrušiť
|
||||
</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn
|
||||
class="button primary"
|
||||
variant="text"
|
||||
@click="deleteMember()"
|
||||
>
|
||||
Áno
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tmUtils from '@/plugins/tm@_utils/tm.utils'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
member: null,
|
||||
team: null
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async showModal({ member, team }) {
|
||||
this.member = member
|
||||
this.team = team
|
||||
this.visible = true
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.visible = false
|
||||
},
|
||||
|
||||
async deleteMember() {
|
||||
this.team.employees = [...this.team.employees].filter(employee => employee.id !== this.member.id)
|
||||
|
||||
try {
|
||||
if (this.team.id) {
|
||||
const { team } = await this.$axios.put_auth(`v1/teams/${this.team.id}`, this.team)
|
||||
this.$store.commit('tm/update_team', team)
|
||||
} else {
|
||||
const { team } = await this.$axios.post_auth(`v1/teams`, this.team)
|
||||
this.$store.commit('tm/save_team', team)
|
||||
}
|
||||
|
||||
this.$events.emit('master-task:team-member-deleted', { teamId: this.team.id, memberId: this.member.id })
|
||||
this.closeModal()
|
||||
} catch (error) {
|
||||
this.$toast.error(error)
|
||||
}
|
||||
},
|
||||
|
||||
_enrichTeam(team) {
|
||||
team.employees = tmUtils.enrichEmployees(team.employees)
|
||||
return team
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -12,17 +12,33 @@
|
||||
|
||||
<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" :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" />
|
||||
<div class="splitted-inputs">
|
||||
<!-- TODO: Bialko validacie -->
|
||||
<Datepicker v-model="mastertask.deadline" :auto-apply="true" @focus="onDateFocus" :min-date="new Date()" class="modal-input left" format="dd.MM.yyyy" locale="sk" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Dátum"
|
||||
:class="{ error: v$.mastertask.deadline.$errors?.length }" :validations="v$.mastertask.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 class="modal-input right" variant="solo" v-model="mastertask._deadline_time" label="Čas" append-inner-icon="mdi-clock-outline" type="time" @focus="onInputFocus"
|
||||
:class="{ error: v$.mastertask._deadline_time.$errors.length }" :hint="v$.mastertask._deadline_time.$errors ? errorUtils.parseErrors(v$.mastertask._deadline_time.$errors) : null" />
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<v-text-field v-model="mastertask.duration" @focus="onInputFocus" class="modal-input" variant="solo" type="number" :label="`${mastertask.duration} h`"></v-text-field>
|
||||
|
||||
<v-select v-model="mastertask.team_id" @focus="onInputFocus" class="modal-input border-select" :class="{ error: v$.mastertask.employees.$errors.length }" label="Tím" variant="solo" :items="teams" item-value="id" item-title="name"></v-select>
|
||||
|
||||
<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="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">
|
||||
{{ employee.name.charAt(0) + employee.surname.charAt(0) }}
|
||||
{{ employee?.name.charAt(0) + employee?.surname.charAt(0) }}
|
||||
</p>
|
||||
<v-icon @click.stop="removeMemberAlert(employee)" class="remove-input" icon="mdi-close" size="small"></v-icon>
|
||||
</v-text-field>
|
||||
</template>
|
||||
<template v-if="!mastertask.id && !mastertask.team_id && mastertask.employees">
|
||||
<v-text-field v-for="(employee, index) in mastertask.employees" :key="employee.id" @focus="onInputFocus" 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">
|
||||
{{ employee?.name.charAt(0) + employee?.surname.charAt(0) }}
|
||||
</p>
|
||||
<!-- <v-icon @click.stop="removeMemberAlert(employee)" class="remove-input" icon="mdi-close" size="small"></v-icon> -->
|
||||
</v-text-field>
|
||||
</template>
|
||||
|
||||
@@ -30,7 +46,7 @@
|
||||
|
||||
<!-- <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" :class="{error: v$.mastertask.project_id.$errors.length}" @click="showAddEmployeeInput = true"> <v-icon class="mx-1" icon="mdi-plus" />Pridať zamestnanca </v-btn>
|
||||
|
||||
<div class="w-100 modal-input" :class="{ error: v$.mastertask.description.$errors.length }">
|
||||
<QuillEditor ref="description" v-model="mastertask.description" placeholder="Popis" theme="snow" class="rich-text-editor" @input="mastertask.description = $event.srcElement.innerHTML" />
|
||||
@@ -114,6 +130,7 @@ export default {
|
||||
|
||||
data() {
|
||||
return {
|
||||
deadline: null,
|
||||
editMode: false,
|
||||
visible: false,
|
||||
errorUtils,
|
||||
@@ -153,15 +170,23 @@ export default {
|
||||
return {
|
||||
mastertask: {
|
||||
project_id: { required },
|
||||
team_id: { required },
|
||||
employees: { required },
|
||||
name: { required },
|
||||
description: { required },
|
||||
deadline: { required }
|
||||
deadline: { required },
|
||||
_deadline_time: { required }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$events.on('master-task:team-member-deleted', ({ teamId, memberId }) => {
|
||||
if (this.mastertask.team_id != teamId)
|
||||
return
|
||||
|
||||
this.mastertask.employees = this.mastertask.employees.filter(employee => employee.id != memberId)
|
||||
}),
|
||||
|
||||
this.$events.on('on-mastertask-deleted', (mastertask) => {
|
||||
if (mastertask?.id == this.mastertask?.id) this.closeModal()
|
||||
})
|
||||
@@ -186,14 +211,22 @@ export default {
|
||||
this.$events.off('on-mastertask-deleted')
|
||||
this.$events.off('on-subtask-deleted')
|
||||
this.$events.off('on-subtask-edited')
|
||||
this.$events.off('master-task:team-member-deleted')
|
||||
},
|
||||
|
||||
methods: {
|
||||
removeMemberAlert(member) {
|
||||
const team = this.mastertask.team
|
||||
this.$events.emit('show-delete-team-member-modal', { member, team })
|
||||
},
|
||||
|
||||
async showModal({mastertask, editMode = false}) {
|
||||
this.editMode = null
|
||||
this.visible = true
|
||||
this.mastertask = null
|
||||
this.$nextTick(() => this.v$.$reset())
|
||||
this.$nextTick(() => {
|
||||
this.v$.$reset()
|
||||
})
|
||||
|
||||
try {
|
||||
if (mastertask?.id) {
|
||||
@@ -206,7 +239,7 @@ export default {
|
||||
|
||||
// this.mastertask.project_code = project.code
|
||||
} else {
|
||||
this.mastertask = { employees: [], duration: 0 }
|
||||
this.mastertask = { employees: [], duration: 0, _deadline_time: '17:00' }
|
||||
}
|
||||
|
||||
this.editMode = editMode || !this.mastertask.id
|
||||
@@ -226,6 +259,8 @@ export default {
|
||||
if (this.$refs['description'])
|
||||
this.mastertask.description = this.$refs['description'].getHTML()
|
||||
|
||||
this._mergeDeadlineTimeDate()
|
||||
|
||||
try {
|
||||
this.mastertask.deadline = moment(this.mastertask.deadline).format('YYYY-MM-DD HH:MM:SS')
|
||||
|
||||
@@ -253,6 +288,15 @@ export default {
|
||||
|
||||
addTask() {
|
||||
this.$events.emit('show-subtask-modal', { subtask: null, editMode: false, mastertask: this.mastertask })
|
||||
},
|
||||
|
||||
_mergeDeadlineTimeDate() {
|
||||
const date = new Date(this.mastertask.deadline);
|
||||
const timeParts = this.mastertask._deadline_time.split(':');
|
||||
date.setHours(parseInt(timeParts[0]));
|
||||
date.setMinutes(parseInt(timeParts[1]));
|
||||
|
||||
this.mastertask.deadline = date
|
||||
}
|
||||
},
|
||||
|
||||
@@ -260,6 +304,14 @@ export default {
|
||||
editMode() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs['description']?.setHTML(this.mastertask.description || '')
|
||||
|
||||
if (!this.mastertask) return
|
||||
|
||||
const date = new Date(this.mastertask.deadline)
|
||||
const hours = date.getHours()
|
||||
const minutes = date.getMinutes()
|
||||
|
||||
this.mastertask._deadline_time = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -267,6 +319,15 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="sass" scoped>
|
||||
.date-wrap
|
||||
display: flex
|
||||
flex-flow: row
|
||||
width: 100%
|
||||
gap: 20px
|
||||
|
||||
.dp__main
|
||||
width: calc(50% - 10px) !important
|
||||
|
||||
.employee-select-avatar
|
||||
background: #6200EE
|
||||
color: #fff
|
||||
@@ -278,14 +339,20 @@ export default {
|
||||
position: absolute
|
||||
top: 50%
|
||||
right: 0
|
||||
transform: translate(-50%, -50%)
|
||||
transform: translate(-120%, -50%)
|
||||
|
||||
.remove-input
|
||||
position: absolute
|
||||
top: 50%
|
||||
transform: translate(120%, -50%)
|
||||
cursor: pointer
|
||||
|
||||
.scrolling
|
||||
overflow: hidden !important
|
||||
|
||||
.border-bottom
|
||||
border-bottom: 1px solid rgba(0,0,0,.1)
|
||||
|
||||
|
||||
.subtask-btn
|
||||
border: thin solid rgba(var(--v-border-color), var(--v-border-opacity)) !important
|
||||
color: #7f39fb !important
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
<p class="task-badge rounded-pill">Pridať záznam</p>
|
||||
</div>
|
||||
|
||||
<div v-for="timeblock in timeblocks" :key="timeblock.id" class="d-flex align-center mb-3">
|
||||
<v-icon @click.stop="deleteTimeblock(timeblock)" class="circle-border cursor-pointer mr-2" icon="mdi-minus" size="medium" />
|
||||
<div v-for="(timeblock, index) in timeblocks" :key="timeblock.id" class="d-flex align-center mb-3">
|
||||
<v-icon @click.stop="subtask.id ? deleteTimeblock(timeblock) : deleteTimeblockWithoutId(index)" class="circle-border cursor-pointer mr-2" icon="mdi-minus" size="medium" />
|
||||
<p class="task-badge rounded-pill" :class="{'strike-through': timeblock.is_finished}">{{ tmUtils.formatDateTime(timeblock.start) }} - {{ tmUtils.formatDateTime(timeblock.end) }}</p>
|
||||
<v-icon @click.stop="toggleTimeblockIsFinished(timeblock)" class="circle-border cursor-pointer ml-2" :class="{'completed': timeblock.is_finished}" icon="mdi-check" size="medium" />
|
||||
<v-icon v-show="subtask.id" @click.stop="toggleTimeblockIsFinished(timeblock)" class="circle-border cursor-pointer ml-2" :class="{'completed': timeblock.is_finished}" icon="mdi-check" size="medium" />
|
||||
</div>
|
||||
</v-sheet>
|
||||
</v-col>
|
||||
@@ -107,12 +107,22 @@ export default {
|
||||
const start = moment(this.form.date).hours(parseInt(splittedStartsAtTime[0])).minutes(parseInt(splittedStartsAtTime[1])).toISOString()
|
||||
const end = moment(this.form.date).hours(parseInt(splittedEndsAtTime[0])).minutes(parseInt(splittedEndsAtTime[1])).toISOString()
|
||||
|
||||
if (!subtask?.timeblocks) { subtask.timeblocks = [] }
|
||||
if (!subtask?.timesheets) { subtask.timesheets = [] }
|
||||
if (!subtask?.is_finished) { subtask.is_finished = 0 }
|
||||
|
||||
subtask.timeblocks.push({
|
||||
id: null,
|
||||
start: tmUtils.formatDateTimeForBackend(start),
|
||||
end: tmUtils.formatDateTimeForBackend(end)
|
||||
})
|
||||
|
||||
if (!subtask.id) {
|
||||
this.$emit('update-unfinished-subtask', subtask)
|
||||
this.closeModal()
|
||||
return
|
||||
}
|
||||
|
||||
this._update(subtask)
|
||||
},
|
||||
|
||||
@@ -150,6 +160,10 @@ export default {
|
||||
this._update(subtask)
|
||||
},
|
||||
|
||||
deleteTimeblockWithoutId(i) {
|
||||
this.$emit('delete-timeblock')
|
||||
},
|
||||
|
||||
async _update(data) {
|
||||
try {
|
||||
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${data.id}`, data)
|
||||
|
||||
@@ -14,6 +14,27 @@
|
||||
|
||||
<v-text-field v-model="subtask.title" @focus="onInputFocus" class="modal-input" label="Názov subtasku" variant="solo"></v-text-field>
|
||||
|
||||
<div class="splitted-inputs">
|
||||
<!-- TODO: Bialko validacie -->
|
||||
<Datepicker v-model="subtask.deadline" :auto-apply="true" @focus="onDateFocus" :min-date="new Date()" class="modal-input left" format="dd.MM.yyyy" locale="sk" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Dátum"
|
||||
:class="{ error: v$.subtask.deadline.$errors?.length }" :validations="v$.subtask.deadline" />
|
||||
|
||||
<v-text-field class="modal-input right" variant="solo" v-model="subtask._deadline_time" label="Čas" append-inner-icon="mdi-clock-outline" type="time" @focus="onInputFocus"
|
||||
:class="{ error: v$.subtask._deadline_time.$errors.length }" :hint="v$.subtask._deadline_time.$errors ? errorUtils.parseErrors(v$.subtask._deadline_time.$errors) : null" />
|
||||
</div>
|
||||
|
||||
<!-- TODO: Toto tu nema byt ci? -->
|
||||
<!-- <div class="w-full">
|
||||
<A-task-timeblocks
|
||||
class="w-full"
|
||||
:timeblocks="subtask.timeblocks"
|
||||
:subtask="subtask"
|
||||
@update-subtask="$emit('update-subtask')"
|
||||
@update-unfinished-subtask="subtask = $event"
|
||||
@delete-timeblock="deleteTimeblock($event)"
|
||||
/>
|
||||
</div> -->
|
||||
|
||||
<template v-if="subtask.id">
|
||||
<v-autocomplete v-model="subtask.employee_id" label="Priradený" :items="enrichedEmployees" item-title="_fullName" item-value="id" variant="solo" class="modal-input" :class="{ error: employeeValidations[0]?.employee }"
|
||||
@update:model-value="employeeValidations[0] ? employeeValidations[0].employee = false : null" />
|
||||
@@ -22,10 +43,10 @@
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div v-for="(employee, index) in subtask.employees" :key="`employee-${index}`" class="multiple-employee-select">
|
||||
<v-autocomplete v-model="employee.id" label="Priradený" :items="enrichedEmployees" item-title="_fullName" item-value="id" variant="solo" class="modal-input employee" :class="{ error: employeeValidations[index]?.employee }"
|
||||
<div v-for="(employee, index) in subtask.employees" :key="`employee-${index}`" class="splitted-inputs">
|
||||
<v-autocomplete v-model="employee.id" label="Priradený" :items="enrichedEmployees" item-title="_fullName" item-value="id" variant="solo" class="modal-input left" :class="{ error: employeeValidations[index]?.employee }"
|
||||
@update:model-value="employeeValidations[index] ? employeeValidations[index].employee = false : null" />
|
||||
<v-text-field v-model="employee.duration" class="modal-input duration" variant="solo" type="number" label="Časový odhad" append-inner-icon="mdi-clock-outline" :class="{ error: employeeValidations[index]?.duration }" @focus="onInputFocus"
|
||||
<v-text-field v-model="employee.duration" class="modal-input right" variant="solo" type="number" label="Časový odhad" append-inner-icon="mdi-clock-outline" :class="{ error: employeeValidations[index]?.duration }" @focus="onInputFocus"
|
||||
@update:model-value="employeeValidations[index] ? employeeValidations[index].duration = false : null" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -60,6 +81,13 @@
|
||||
<v-card-actions class="d-flex flex-column modal-content">
|
||||
<div class="w-100">
|
||||
<Z-task-readonly-info :subtask="subtask" @close-modal="closeModal" @update-subtask="updateSubtask" />
|
||||
<!-- <div class="mt-10">
|
||||
<p>Termín</p>
|
||||
<div class="date-wrap">
|
||||
<Datepicker @open="editDatepicker('date')" v-model="subtask.deadline" @focus="onDateFocus" :min-date="new Date()" class="modal-input" format="dd.MM.yyyy" locale="sk" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Dátum" />
|
||||
<Datepicker @open="editDatepicker('time')" v-model="subtask.deadline" @focus="onDateFocus" :min-date="new Date()" class="modal-input" format="HH:mm" locale="sk" select-text="Vybrať" cancel-text="Zrušiť" placeholder="Čas" />
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="d-flex justify-start align-center mt-8">
|
||||
<v-btn class="done-btn" v-if="!subtask.is_finished" @click.stop="showCompleteTaskModal()">Dokončiť</v-btn>
|
||||
@@ -74,7 +102,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Datepicker from '@vuepic/vue-datepicker'
|
||||
import ZFilesUpload from "@/plugins/tm@_components/z-files-upload.vue"
|
||||
import ATaskTimeblocks from '@/plugins/tm@modal/task/_components/_components/a-task-timeblocks.vue'
|
||||
import useVuelidate from "@vuelidate/core"
|
||||
import { required } from "@vuelidate/validators"
|
||||
import errorUtils from "@/plugins/lib@auth/_utils/error.utils"
|
||||
@@ -95,6 +125,8 @@ export default {
|
||||
components: {
|
||||
ZTaskReadonlyInfo,
|
||||
ZFilesUpload,
|
||||
Datepicker,
|
||||
// ATaskTimeblocks,
|
||||
QuillEditor
|
||||
},
|
||||
|
||||
@@ -124,12 +156,21 @@ export default {
|
||||
return {
|
||||
subtask: {
|
||||
master_task_id: { required },
|
||||
// title: { required }
|
||||
deadline: { required },
|
||||
_deadline_time: { required }
|
||||
// description: { required }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$events.on("add-timeblock", (timeblock) => {
|
||||
if (!this.subtask?.timeblocks) { this.subtask.timeblocks = [] }
|
||||
if (!this.subtask?.timesheets) { this.subtask.timesheets = [] }
|
||||
if (!this.subtask?.is_finished) { this.subtask.is_finished = 0 }
|
||||
this.subtask.timeblocks.push(timeblock)
|
||||
})
|
||||
|
||||
this.$events.on("on-subtask-edited", (subtask) => {
|
||||
if (subtask?.id == this.subtask?.id)
|
||||
this.subtask = this._enrichTask(subtask)
|
||||
@@ -154,15 +195,18 @@ export default {
|
||||
const data = await this.$axios.get_auth_data(`v1/subtasks/${subtask.id}`)
|
||||
this.subtask = this._enrichTask(data)
|
||||
} else {
|
||||
this.subtask = { master_task: mastertask, employees: [{}] }
|
||||
this.subtask = { master_task: mastertask, employees: [{}], _deadline_time: '17:00' }
|
||||
}
|
||||
|
||||
this.editMode = editMode || !this.subtask.id
|
||||
} catch (error) {
|
||||
this.$toast.error(error)
|
||||
}
|
||||
},
|
||||
|
||||
deleteTimeblock(i) {
|
||||
this.subtask.timeblocks.splice(i, 1)
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.visible = false
|
||||
this.$router.replace({name: this.$route.name})
|
||||
@@ -171,10 +215,11 @@ export default {
|
||||
async save() {
|
||||
const employeesValid = await this._validateEmployees()
|
||||
|
||||
if (!(await this.v$.$validate()) || !employeesValid)
|
||||
return
|
||||
if (!(await this.v$.$validate())) return
|
||||
if (!employeesValid) return
|
||||
|
||||
this.subtask.description = this.$refs['description'].getHTML()
|
||||
this._mergeDeadlineTimeDate()
|
||||
|
||||
try {
|
||||
if (this.subtask?.id) {
|
||||
@@ -194,6 +239,7 @@ export default {
|
||||
|
||||
this.closeModal()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
this.$toast.error(error)
|
||||
}
|
||||
},
|
||||
@@ -224,6 +270,15 @@ export default {
|
||||
this.subtask = subtask
|
||||
},
|
||||
|
||||
_mergeDeadlineTimeDate() {
|
||||
const date = new Date(this.subtask.deadline);
|
||||
const timeParts = this.subtask._deadline_time.split(':');
|
||||
date.setHours(parseInt(timeParts[0]));
|
||||
date.setMinutes(parseInt(timeParts[1]));
|
||||
|
||||
this.subtask.deadline = date
|
||||
},
|
||||
|
||||
_validateEmployees() {
|
||||
return new Promise((resolve) => {
|
||||
this.employeeValidations = []
|
||||
@@ -308,6 +363,19 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="sass" scoped>
|
||||
.w-full
|
||||
width: 100%
|
||||
|
||||
.date-wrap
|
||||
display: flex
|
||||
flex-flow: row
|
||||
width: 100%
|
||||
gap: 20px
|
||||
margin-bottom: 20px
|
||||
|
||||
.dp__main
|
||||
width: calc(50% - 10px) !important
|
||||
|
||||
.scrolling
|
||||
overflow: hidden !important
|
||||
|
||||
@@ -324,17 +392,4 @@ export default {
|
||||
@media screen and (max-width: 522px)
|
||||
.files
|
||||
margin-top: 104px !important
|
||||
|
||||
.multiple-employee-select
|
||||
width: 100%
|
||||
|
||||
.modal-input
|
||||
display: inline-block
|
||||
|
||||
.employee
|
||||
width: 70% !important
|
||||
|
||||
.duration
|
||||
width: 25% !important
|
||||
margin-left: 5%
|
||||
</style>
|
||||
Reference in new issue
Block a user