Merge branch 'main' of bitbucket.org:studiotem/jandl-taskmanager-app

This commit is contained in:
StudioTem committed 2023-02-23 07:39:37 +01:00
commit 7dfc6db0d7
41 files changed
+198 -137

No files matched your search

+35 -12
View File
@@ -1,4 +1,5 @@
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
import store from '@/store'
const routes: Array<RouteRecordRaw> = [
{
@@ -16,17 +17,20 @@ const routes: Array<RouteRecordRaw> = [
{
path: '/auth/login',
name: 'Login',
component: () => import('@/plugins/lib@auth/login/login.vue')
component: () => import('@/plugins/lib@auth/login/login.vue'),
meta: {requiresAuth: false}
},
{
path: '/auth/forgot-password',
name: 'Forgot password',
component: () => import('@/plugins/lib@auth/forgot-password/forgot-password.vue')
component: () => import('@/plugins/lib@auth/forgot-password/forgot-password.vue'),
meta: {requiresAuth: false}
},
{
path: '/auth/reset-password',
name: 'Reset password',
component: () => import('@/plugins/lib@auth/reset-password/reset-password.vue')
component: () => import('@/plugins/lib@auth/reset-password/reset-password.vue'),
meta: {requiresAuth: false}
}
]
},
@@ -45,50 +49,50 @@ const routes: Array<RouteRecordRaw> = [
{
path: '/app/dashboard/tasks',
name: 'Dashboard - Tasks',
meta: { title: 'Tasks' },
meta: { title: 'Tasks', requiresAuth: true },
component: () => import('@/plugins/tm@dashboard/tasks/tasks.vue')
},
{
path: '/app/dashboard/teams',
name: 'Dashboard - Teams',
meta: { title: 'Teams Overview' },
meta: { title: 'Teams Overview', requiresAuth: true },
component: () => import('@/plugins/tm@dashboard/teams/teams.vue')
},
{
path: '/app/dashboard/projects',
name: 'Dashboard - Projects',
meta: { title: 'Projects overview' },
meta: { title: 'Projects overview', requiresAuth: true },
component: () => import('@/plugins/tm@dashboard/projects/projects.vue')
},
{
path: '/app/overview/unscheduled',
name: 'Overview - Unscheduled tasks',
meta: { title: 'Unscheduled tasks' },
meta: { title: 'Unscheduled tasks', requiresAuth: true },
component: () => import('@/plugins/tm@overview/tasks-unscheduled/tasks-unscheduled.vue')
},
{
path: '/app/overview/ongoing',
name: 'Overview - Ongoing tasks',
meta: { title: 'Ongoing tasks' },
meta: { title: 'Ongoing tasks', requiresAuth: true },
component: () => import('@/plugins/tm@overview/tasks-ongoing/tasks-ongoing.vue')
},
{
path: '/app/overview/teams',
name: 'Overview - Teams',
meta: { title: 'Teams' },
meta: { title: 'Teams', requiresAuth: true },
component: () => import('@/plugins/tm@overview/teams/teams.vue')
},
{
path: '/app/dashboard/user',
name: 'Dashboard - User',
meta: { title: 'Profile' },
meta: { title: 'Profile', requiresAuth: true },
component: () => import('@/plugins/tm@profile/profile/my-profile.vue')
},
{
path: '/app/search',
name: 'Search',
meta: { title: 'Search Results' },
meta: { title: 'Search Results', requiresAuth: true },
component: () => import('@/plugins/lib@search/search/search.vue')
}
]
@@ -98,7 +102,8 @@ const routes: Array<RouteRecordRaw> = [
{
path: '/:catchAll(.*)',
name: '404',
component: () => import('@/plugins/w@screen/404/404.vue')
component: () => import('@/plugins/w@screen/404/404.vue'),
meta: {requiresAuth: null}
}
]
@@ -107,4 +112,22 @@ const router = createRouter({
routes
})
router.beforeEach((to, from, next) => {
const isLoggedIn = store.getters['auth/isLoggedIn']
if (to.meta.requiresAuth === true) {
if (isLoggedIn)
return next()
else
return next({name: 'Login'})
} else if (to.meta.requiresAuth === false) {
if (!isLoggedIn)
return next()
else
return next({name: 'Dashboard - Tasks'})
} else {
return next({name: 'Login'})
}
})
export default router
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" class="ionicon" viewBox="0 0 512 512"><title>Eye</title><path d="M255.66 112c-77.94 0-157.89 45.11-220.83 135.33a16 16 0 00-.27 17.77C82.92 340.8 161.8 400 255.66 400c92.84 0 173.34-59.38 221.79-135.25a16.14 16.14 0 000-17.47C428.89 172.28 347.8 112 255.66 112z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><circle cx="256" cy="256" r="80" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/></svg>

After

Width:  |  Height:  |  Size: 518 B

@@ -6,7 +6,7 @@
<h1>{{ $route.meta.title }}</h1>
<div class="d-flex justify-end align-center w-100 header-sm">
<img class="search-icon" :src="require('@/plugins/app/_layout/app/_img/search-icon.svg')" alt="search-icon" />
<img class="search-icon" :src="require('@/plugins/app/_img/icons/search.svg')" alt="search-icon" />
<input class="search-input mx-2" v-model="search" type="text" placeholder="Search" @click="$router.push({name: 'Search'})" @keyup="$events.emit('onSearch', search)" />
<v-menu>
@@ -3,7 +3,7 @@
<ion-content>
<img
class="py-5 px-5 cursor-pointer"
:src="require('@/plugins/app/_layout/_img/jandl-logo.svg')"
:src="require('@/plugins/app/_img/jandl-logo.svg')"
alt="jandl-logo"
@click="refreshPage()"
/>
@@ -1,7 +1,7 @@
<template>
<header class="login-header-border ">
<v-container>
<img :src="require('@/plugins/app/_layout/_img/jandl-logo.svg')" alt="jandl-logo">
<img :src="require('@/plugins/app/_img/jandl-logo.svg')" alt="jandl-logo">
</v-container>
</header>
</template>
+7
View File
@@ -5,17 +5,24 @@
margin-left: 12px
border-radius: 50%
cursor: pointer
max-height: 32px
max-width: 32px
.pencil-icon
padding: 10px
background: rgba(0, 0, 0, 0.04)
border-radius: 50%
cursor: pointer
max-height: 32px
max-width: 32px
.status-badge
background: #F2E7FE
color: #7F39FB
width: fit-content
.hover
cursor: pointer !important
.task-badge
background: rgba(0, 0, 0, 0.04)
width: fit-content
@@ -14,9 +14,9 @@
</td>
<td class="task-action">
<div class="d-flex justify-start">
<img class="pencil-icon" :src="require('@/plugins/tm@dashboard/_components/_img/checkmark.svg')" alt="checkmark-icon">
<img class="pencil-icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon">
<img class="trash-icon" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon">
<img class="pencil-icon" :src="require('@/plugins/app/_img/icons/checkmark.svg')" alt="checkmark-icon">
<img class="pencil-icon" :src="require('@/plugins/app/_img/icons/pencil.svg')" alt="pencil-icon">
<img class="trash-icon" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon">
</div>
</td>
</tr>
@@ -7,8 +7,8 @@
<td>{{ team.name }}</td>
<td class="task-action">
<div class="d-flex justify-start">
<img class="pencil-icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon" @click.stop="editTeam(team)" />
<img class="trash-icon" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon" @click.stop="deleteTeam(team)" />
<img class="pencil-icon" :src="require('@/plugins/app/_img/icons/pencil.svg')" alt="pencil-icon" @click.stop="editTeam(team)" />
<img class="trash-icon" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="deleteTeam(team)" />
</div>
</td>
</tr>
+6 -6
View File
@@ -1,8 +1,6 @@
import axios from '@/plugins/w@custom/axios/models/axios'
import store from '@/store'
import ax from 'axios'
export default {
namespaced: true,
@@ -25,10 +23,10 @@ export default {
state.employees = employees
// TODO: Remove
const employee = employees.find(employee => employee.email == 'zachariah.vonrueden@jandl.sk')
store.commit('auth/auth_success', {
user: employee
})
// const employee = employees.find(employee => employee.email == 'zachariah.vonrueden@jandl.sk')
// store.commit('auth/auth_success', {
// user: employee
// })
},
set_teams(state: any, teams: any) {
@@ -67,6 +65,7 @@ export default {
update_subtask(state: any, subtask: any) {
state.unscheduledSubtasks = state.unscheduledSubtasks.map(st => st.id == subtask.id ? subtask : st)
state.ongoingSubtasks = state.ongoingSubtasks.map(st => st.id == subtask.id ? subtask : st)
state.mastertasks = state.mastertasks.map(mastertask => {
mastertask.subtasks = mastertask.subtasks.map(st => st.id == subtask.id ? subtask : st)
return mastertask
@@ -76,6 +75,7 @@ export default {
delete_subtask(state: any, subtask: any) {
state.unscheduledSubtasks = state.unscheduledSubtasks.filter(st => st.id != subtask.id)
state.ongoingSubtasks = state.ongoingSubtasks.filter(st => st.id != subtask.id)
state.mastertasks = state.mastertasks.map(mastertask => {
mastertask.subtasks = mastertask.subtasks.filter(st => st.id != subtask.id)
return mastertask
@@ -26,11 +26,11 @@
<template v-slot:split-label="{ split }">
<div class="w-100 h-100 d-flex flex-column">
<span v-if="split.date" class="d-flex align-center">
<img v-if="getHeadingDate(split.date) == 'Dnes'" :src="require('./_img/home-icon.svg')" class="mr-2">
<img v-if="getHeadingDate(split.date) == 'Dnes'" :src="require('@/plugins/app/_img/icons/home.svg')" class="mr-2">
<p class="weekday-label">{{ getHeadingDate(split.date) }}</p>
</span>
<span v-else class="d-flex align-center">
<p class="weekday-label">{{ split.firstName }}</p>
<p class="weekday-label">{{ split.name }}</p>
</span>
<span v-if="split.date">
@@ -42,7 +42,7 @@
<p>{{ split.initials }}</p>
</div>
<div>
<p class="mb-0 mt-0 unscheduled-time-name">{{split.name}}</p>
<p class="mb-0 mt-0 unscheduled-time-name">{{split.fullname}}</p>
<h1 class="mb-0 mt-0">{{split.unscheduledTime}} h</h1>
</div>
</div>
@@ -58,26 +58,26 @@
<template v-slot:event="{ event }">
<!-- <div v-if="!event.nonWorking" @click.stop="editTask(event.id)" class="w-100 h-100 d-flex flex-column justify-space-between" :class="{'short-event' : getEventLenght(event) <= 9000000, 'mini-event' : getEventLenght(event) <= 5400000, 'micro-event' : getEventLenght(event) <= 3600000}"> -->
<div v-if="!event.nonWorking" class="w-100 h-100 d-flex flex-column justify-space-between" :class="{'short-event' : getEventLenght(event) <= 9000000, 'mini-event' : getEventLenght(event) <= 5400000, 'micro-event' : getEventLenght(event) <= 3600000}">
<div v-if="!event.nonWorking" class="custom-event-body w-100 h-100 d-flex flex-column justify-space-between" :class="{'short-event' : getEventLenght(event) <= 9000000, 'mini-event' : getEventLenght(event) <= 5400000, 'micro-event' : getEventLenght(event) <= 3600000}" :style="{backgroundColor: event.subtask.color}">
<div class="event-content">
<small v-if="(event.subtask.project_code && !event.is_blocker)" class="project-code">{{ event.subtask.project_code }}</small>
<h3>{{ event.subtask.master_task?.name || event.subtask.master_task }}</h3>
<div class="d-flex align-center event-details event-initials-wrapper">
<div class="event-initials d-flex justify-center align-center">
<small>{{ getUserInitials(event) }}</small>
<small>{{ event.initials }}</small>
</div>
<small class="event-initials-date">{{ event.start.toLocaleDateString('sk-SK') }}</small>
</div>
</div>
<div class="event-footer d-flex">
<v-btn rounded class="event-footer-button me-2" :class="{'completed': event.subtask.is_finished}" @click.stop="completeTask(event)"><img :src="require('./_img/checkmark.svg')" alt=""></v-btn>
<v-btn rounded class="event-footer-button me-2" @click.stop="editTask(event, true)"><img :src="require('./_img/pencil.svg')" alt=""></v-btn>
<v-btn rounded class="event-footer-button me-2" @click.stop="deleteTask(event)"><img :src="require('./_img/bin.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="deleteTask(event)"><img :src="require('@/plugins/app/_img/icons/bin.svg')" alt=""></v-btn>
</div>
</div>
<div v-else class="non-working-event w-100 h-100 d-flex flex-column justify-center">
<div v-else class="custom-event-body non-working-event w-100 h-100 d-flex flex-column justify-center">
<div class="d-flex justify-center align-center">
<v-icon icon="mdi-cancel" color="black"></v-icon>
<h3 class="mb-0 ms-2">{{ event.title }}</h3>
@@ -189,10 +189,6 @@ export default {
return date.toLocaleDateString('sk-SK')
},
getUserInitials(event) {
return event.name.charAt(0).toUpperCase() + event.surname.charAt(0).toUpperCase()
},
getEventLenght(event) {
return event.end.getTime() - event.start.getTime()
},
@@ -356,12 +352,15 @@ export default {
.vuecal__event
border-radius: 16px
padding: 20px 10px
// padding: 20px 10px
text-align: left
background: rgba(248, 248, 248, 1)
min-height: 40px
transition: min-height .4s, height .4s, box-shadow .4s, width .4s, left .4s
.custom-event-body
padding: 20px 10px
&:has(.completed)
background: rgb(251, 251, 251) !important
border: 1px solid #cccccc !important
@@ -10,7 +10,7 @@
variant="outlined"
></v-select>
<div class="d-flex date-wrapper">
<v-btn class="subheader-icon-button prev" variant="outlined" @click="prevWeek()"><img :src="require('@/plugins/tm@dashboard/_components/_img/icon-prev.svg')" alt=""></v-btn>
<v-btn class="subheader-icon-button prev" variant="outlined" @click="prevWeek()"><img :src="require('@/plugins/app/_img/icons/icon-prev.svg')" alt=""></v-btn>
<v-text-field
class="subheader-input disabled"
label="Dátum"
@@ -18,7 +18,7 @@
variant="outlined"
append-inner-icon="mdi-calendar-blank-outline"
></v-text-field>
<v-btn class="subheader-icon-button next" variant="outlined" @click="nextWeek()"><img :src="require('@/plugins/tm@dashboard/_components/_img/icon-next.svg')" alt=""></v-btn>
<v-btn class="subheader-icon-button next" variant="outlined" @click="nextWeek()"><img :src="require('@/plugins/app/_img/icons/icon-next.svg')" alt=""></v-btn>
</div>
<v-text-field
class="subheader-input disabled"
@@ -40,8 +40,6 @@ export default {
start: addDays(new Date(timeblock.start), diffInDays),
end: addDays(new Date(timeblock.end), diffInDays),
master_task: subtask.master_task,
name: employee.name,
surname: employee.surname,
date: new Date(timeblock.start),
isWeekend: this.isWeekend(timeblock.start),
initials: employee.name.charAt(0).toUpperCase() + employee.surname.charAt(0).toUpperCase(),
@@ -80,5 +78,11 @@ export default {
_getSplitFromDate(date, start) {
return differenceInCalendarDays(new Date(date), new Date(start)) * (-1) + 1
},
_getDifferenceInHours(date1, date2) {
let diff =(date1.getTime() - date2.getTime()) / 1000;
diff /= (60 * 60)
return Math.abs(Math.round(diff))
}
}
+15 -2
View File
@@ -12,6 +12,7 @@ import { addDays, subDays } from 'date-fns'
import { mapGetters } from 'vuex'
import moment from 'moment'
import timelineUtils from './_utils/timeline.utils'
import tmUtils from '@/plugins/tm@_utils/tm.utils'
export default {
components: {
@@ -33,13 +34,24 @@ export default {
computed: {
splitDays() {
const days = []
const workingHours = {}
this.timelineData.tasks.forEach(task => {
if (!workingHours[task.split])
workingHours[task.split] = 0
if (task.nonWorking || task.subtask.is_finished)
return
workingHours[task.split] += timelineUtils._getDifferenceInHours(task.end, task.start)
})
for (let i = 0; i < 7; i++) {
days.push({
id: i + 1,
name: 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(),
unscheduledTime: this.timelineData.unscheduledTime,
unscheduledTime: workingHours[i + 1],
date: addDays(this.filter.start, i),
isWeekend: timelineUtils.isWeekend(addDays(this.filter.start, i))
})
@@ -95,6 +107,7 @@ export default {
try {
const { subtasks } = await this.$axios.get_auth(`v1/subtasks?${queryParameters}`)
this.config.scrollHour = this.filter.employee.work_start - 1
this.config.date = this.filter.start
this.subtasks = subtasks
} catch (error) {
this.$toast.error('Nepodarilo sa nacitat data!')
@@ -10,7 +10,7 @@
variant="outlined"
></v-select>
<div class="d-flex date-wrapper">
<v-btn class="subheader-icon-button prev" variant="outlined" @click="prevDay()"><img :src="require('@/plugins/tm@dashboard/_components/_img/icon-prev.svg')" alt=""></v-btn>
<v-btn class="subheader-icon-button prev" variant="outlined" @click="prevDay()"><img :src="require('@/plugins/app/_img/icons/icon-prev.svg')" alt=""></v-btn>
<v-text-field
class="subheader-input disabled"
label="Dátum"
@@ -18,13 +18,14 @@
variant="outlined"
append-inner-icon="mdi-calendar-blank-outline"
></v-text-field>
<v-btn class="subheader-icon-button next" variant="outlined" @click="nextDay()"><img :src="require('@/plugins/tm@dashboard/_components/_img/icon-next.svg')" alt=""></v-btn>
<v-btn class="subheader-icon-button next" variant="outlined" @click="nextDay()"><img :src="require('@/plugins/app/_img/icons/icon-next.svg')" alt=""></v-btn>
</div>
<v-text-field
class="subheader-input disabled"
label="Nenaplánované hodiny"
v-model="time"
variant="outlined"
:disabled="true"
></v-text-field>
</v-row>
</template>
+28 -20
View File
@@ -10,8 +10,9 @@
import ATeamFilter from './_components/a-team-filter.vue'
import ZTimeline from '@/plugins/tm@dashboard/_components/z-timeline.vue'
import { setHours, setMinutes } from 'date-fns'
import { setHours, setMinutes, addDays } from 'date-fns'
import moment from 'moment'
import timelineUtils from '../tasks/_utils/timeline.utils'
export default {
components: {
@@ -35,30 +36,36 @@ export default {
const days = []
this.filter.team.employees.forEach((employee, index) => {
let workingHours = 0
this.timelineData.tasks.forEach(task => {
if (task?.subtask?.employee_id == employee.id)
workingHours += timelineUtils._getDifferenceInHours(task.end, task.start)
})
days.push({
id: index,
name: `${employee.name} ${employee.surname}`,
id: index + 1,
name: employee.name,
fullname: `${employee.name} ${employee.surname}`,
initials: employee.name.charAt(0).toUpperCase() + employee.surname.charAt(0).toUpperCase(),
unscheduledTime: 111
unscheduledTime: workingHours
})
})
return days
},
unscheduledTime() {
return 222
// if (!this.subtasks) return 0
// return timelineUtils.getUnscheduledTime(this.subtasks)
},
timelineData() {
if (!this.subtasks)
return
console.log([...this._generateNonWorking(), ...this._generateTasks()])
// let unscheduledTime = 0
// const tasks = [...this._generateNonWorking(), ...this._generateTasks()]
// tasks.forEach(task => {
// if (!task.nonWorking)
// workingHours += timelineUtils._getDifferenceInHours(task.end, task.start)
// })
return {
unscheduledTime: 333,
@@ -79,7 +86,7 @@ export default {
this.filter.team.employees.forEach((e, index) => {
if (e.id == subtask.employee_id) {
split = index
split = index + 1
employee = e
}
})
@@ -93,11 +100,11 @@ export default {
start: new Date(timeblock.start),
end: new Date(timeblock.end),
master_task: subtask.master_task,
name: employee.name,
surname: employee.surname,
name: employee?.name,
surname: employee?.surname,
// date: new Date(timeblock.start),
isWeekend: moment(timeblock.start).day() % 6 == 0,
initials: employee.name.charAt(0).toUpperCase() + employee.surname.charAt(0).toUpperCase(),
initials: employee?.name?.charAt(0)?.toUpperCase() + employee?.surname?.charAt(0)?.toUpperCase(),
split: split,
project_code: subtask.project_code,
subtask: subtask,
@@ -112,8 +119,9 @@ export default {
_generateNonWorking() {
const tasks = []
let earliestStartHour = null
const date = new Date(this.filter.start)
let earliestStartHour = null
this.config.date = date
this.filter.team.employees.forEach((employee, index) => {
if (!earliestStartHour || employee.work_start < earliestStartHour)
@@ -123,7 +131,7 @@ export default {
title: "Non working hours",
start: setMinutes(setHours(date, 0), 0),
end: setMinutes(setHours(date, employee.work_start), 0),
split: index,
split: index + 1,
nonWorking: true,
draggable: false
})
@@ -132,7 +140,7 @@ export default {
title: "Non working hours",
start: setMinutes(setHours(date, employee.work_end), 0),
end: setMinutes(setHours(date, 23), 59),
split: index,
split: index + 1,
nonWorking: true,
draggable: false
})
@@ -15,10 +15,10 @@
</td>
<td class="task-action">
<div class="d-flex justify-start">
<img v-if="task.is_finished" class="pencil-icon is-finished" :src="require('@/plugins/tm@dashboard/_components/_img/checkmark.svg')" alt="checkmark-icon" @click.stop="clickCompleteTask(task)">
<img v-if="!task.is_finished" class="pencil-icon" :src="require('@/plugins/tm@dashboard/_components/_img/checkmark.svg')" alt="checkmark-icon" @click.stop="clickCompleteTask(task)">
<img class="pencil-icon ml-2" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon" @click.stop="openEditTaskModal(task)">
<img class="trash-icon" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon" @click.stop="openDeleteTaskModal(task)">
<img v-if="task.is_finished" class="pencil-icon is-finished" :src="require('@/plugins/app/_img/icons/checkmark.svg')" alt="checkmark-icon" @click.stop="clickCompleteTask(task)">
<img v-if="!task.is_finished" class="pencil-icon" :src="require('@/plugins/app/_img/icons/checkmark.svg')" alt="checkmark-icon" @click.stop="clickCompleteTask(task)">
<img class="pencil-icon ml-2" :src="require('@/plugins/app/_img/icons/eye.svg')" alt="pencil-icon" @click.stop="openTaskModal(task)">
<img class="trash-icon" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="openDeleteTaskModal(task)">
</div>
</td>
</tr>
@@ -59,26 +59,12 @@ export default {
this.$events.emit('show-delete-task-modal', { task })
},
openEditTaskModal(task) {
openTaskModal(task) {
this.$events.emit('show-task-modal', { task, editMode: false })
},
async clickCompleteTask(task) {
if (!task.is_finished) {
this.openCompleteTaskModal(task)
} else {
task.is_finished = !task.is_finished
try {
await this.$axios.patch_auth(`v1/subtasks/${task.id}`, task)
this.$emit('reopenTask', task)
} catch (error) {
this.$toast.error(error)
}
}
},
openCompleteTaskModal(task) {
this.$events.emit('show-complete-task-modal', { task })
async clickCompleteTask(subtask) {
this.$events.emit('show-complete-task-modal', { subtask })
}
}
}
@@ -42,7 +42,7 @@ export default {
async deleteMasterTask() {
try {
await this.$axios.delete(`v1/mastertasks/${this.masterTask.id}`)
await this.$axios.delete_auth(`v1/mastertasks/${this.masterTask.id}`)
this.$emit('on-master-task-deleted', this.masterTask)
this.closeModal()
} catch (error) {
@@ -48,8 +48,8 @@
<div class="d-flex justify-space-between align-center modal-header border-bottom pb-4">
<h1>{{ masterTask.name }}</h1>
<div class="d-flex justify-start">
<img class="icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon" @click.stop="editMode = !editMode" />
<img class="icon trash" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon" @click.stop="openDeleteMasterTaskModal(masterTask)" />
<img class="icon" :src="require('@/plugins/app/_img/icons/pencil.svg')" alt="pencil-icon" @click.stop="editMode = !editMode" />
<img class="icon trash" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="openDeleteMasterTaskModal(masterTask)" />
</div>
</div>
@@ -61,7 +61,7 @@
<v-btn class="button primary" @click="save()">Ukončiť mastertask</v-btn>
</div>
<A-tasks-table :tasks="masterTask.subtasks" :employees="employees" />
<A-tasks-table :tasks="masterTask.subtasks" :employees="enrichedEmployees" />
<div class="d-flex align-center ">
<v-btn class="subtask-btn w-100" @click="addTask()" ><v-icon class="mx-1" icon="mdi-plus" />Pridať task</v-btn>
@@ -90,6 +90,7 @@ import '@vueup/vue-quill/dist/vue-quill.snow.css'
import SelectsMixin from './_mixins/selects.mixin'
import ATasksTable from './_components/a-tasks-table.vue'
import AMastertaskDescription from './_components/a-mastertask-description.vue'
import { mapGetters } from 'vuex'
export default {
// MIXINS
@@ -115,15 +116,20 @@ export default {
visible: false,
errorUtils,
v$: useVuelidate(),
teams: null,
projects: null,
employees: null,
masterTask: null,
showAddEmployeeInput: false,
date: null,
}
},
computed: {
...mapGetters('tm', [
'teams',
'projects',
'enrichedEmployees'
])
},
validations() {
return {
masterTask: {
@@ -170,11 +176,6 @@ export default {
this.masterTask = null
try {
this.teams = await this.$axios.get_auth_data('v1/teams')
this.projects = await this.$axios.get_auth_data('v1/projects')
const employees = await this.$axios.get_auth_data('v1/employees')
this.employees = tmUtils.enrichEmployeesByFullName(employees)
if (masterTask?.id) {
this.masterTask = await this.$axios.get_auth_data(`v1/mastertasks/${masterTask.id}`)
@@ -10,7 +10,7 @@
</v-col>
<v-col cols="7">
<v-sheet class="py-3">
<p class="task-badge px-4 py-2 rounded-pill">
<p class="task-badge px-4 py-2 rounded-pill hover" @click="openMastertask()" :style="{backgroundColor: color}">
{{ name }}
</p>
</v-sheet>
@@ -20,10 +20,29 @@
<script>
export default {
emits: ['close-modal'],
props: {
name: {
type: String,
required: true
},
id: {
type: Number,
required: true
},
color: {
type: String,
required: true
}
},
methods: {
openMastertask() {
this.$emit('close-modal')
this.$events.emit('show-master-task-modal', {masterTask: {id: this.id}, editMode: false})
}
}
}
@@ -117,7 +117,7 @@ export default {
async _update(task) {
try {
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${task.id}`, task)
this.$store.commit('tm/update_subtask', subtask)
this.closeModal()
this.$events.emit('on-subtask-edited', subtask)
} catch (error) {
@@ -28,7 +28,7 @@
<v-card>
<div class="d-flex justify-space-between align-center">
<h1>Pridať dátum</h1>
<v-icon @click.stop="clsoeModal()" icon="mdi-close" size="large"></v-icon>
<v-icon @click.stop="closeModal()" icon="mdi-close" size="large"></v-icon>
</div>
<v-card-actions class="mt-10 d-flex flex-column modal-content">
@@ -1,5 +1,5 @@
<template>
<A-mastertask-name :name="task.master_task.name" />
<A-mastertask-name :name="task.master_task?.name || task.master_task" :id="task.master_task.id" :color="task.master_task.color" @close-modal="$emit('close-modal')" />
<A-mastertask-status :status="task.is_finished" />
<A-task-timeblocks :timeblocks="task.timeblocks" :task="task" />
<A-task-assigned-employee :employee="task.employee" />
@@ -22,6 +22,8 @@ import ATaskDescription from './_components/a-task-description.vue'
import ZFiles from '@/plugins/tm@modal/_components/z-files.vue'
export default {
emits: ['close-modal'],
components: {
ZFiles,
AMastertaskName,
@@ -2,7 +2,7 @@
<v-dialog v-model="visible" max-width="750">
<v-card>
<div class="d-flex justify-space-between align-center">
<h1>Ste si istý, že chcete {{ this.subtask.is_finished ? 'dokončiť' : 'otvoriť' }} task, z masterTasku <b>{{ subtask?.master_task }}</b>?</h1>
<h1>Ste si istý, že chcete {{ subtask.is_finished ? 'znovu otvoriť' : 'dokončiť' }} task, z masterTasku <b>{{ subtask?.master_task?.name || subtask.master_task }}</b>?</h1>
<v-icon
@click.stop="visible = false"
icon="mdi-close"
@@ -36,12 +36,13 @@ export default {
async complete() {
try {
const tempSubtask = {...this.subtask, is_finished: !this.subtask.is_finished}
const tempSubtask = {...this.subtask, is_finished: this.subtask.is_finished ? 0 : 1}
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${tempSubtask.id}`, tempSubtask)
this.visible = false
this.$store.commit('tm/update_subtask', subtask)
this.$store.dispatch('tm/loadMastertasks')
this.$store.dispatch('tm/loadUnscheduledSubtasks')
this.$store.dispatch('tm/loadOngoingSubtasks')
this.$emit('on-subtask-edited', subtask)
} catch (error) {
this.$toast.error(error)
@@ -42,7 +42,7 @@ export default {
async deleteTask() {
try {
await this.$axios.delete(`v1/subtasks/${this.task.id}`)
await this.$axios.delete_auth(`v1/subtasks/${this.task.id}`)
this.$store.commit('tm/delete_subtask', this.task)
this.$emit('on-task-deleted', this.task)
@@ -34,17 +34,18 @@
<div class="d-flex justify-space-between align-center modal-header border-bottom pb-4">
<h1>{{ task.title }}</h1>
<div class="d-flex justify-start">
<img class="icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon" @click.stop="editMode = !editMode" />
<img class="icon trash" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon" @click.stop="openDeleteTaskModal(task)" />
<img class="icon" :src="require('@/plugins/app/_img/icons/pencil.svg')" alt="pencil-icon" @click.stop="editMode = !editMode" />
<img class="icon trash" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="openDeleteTaskModal(task)" />
</div>
</div>
<v-card-actions class="d-flex flex-column modal-content">
<div class="w-100">
<Z-task-readonly-info :task="task" />
<Z-task-readonly-info :task="task" @close-modal="closeModal" />
<div class="d-flex justify-start align-center mt-8">
<v-btn class="done-btn" @click.stop="task.is_finished = 1; save()">Dokončené</v-btn>
<v-btn class="done-btn" v-if="!task.is_finished" @click.stop="showCompleteTaskModal()">Dokončiť</v-btn>
<v-btn class="button secondary" v-else @click.stop="showCompleteTaskModal()">Znovu otvoriť</v-btn>
<v-btn class="button secondary" @click="save()">Uložiť zmeny</v-btn>
</div>
</div>
@@ -214,6 +215,10 @@ export default {
this.$events.emit("show-delete-task-modal", { task })
},
showCompleteTaskModal() {
this.$events.emit('show-complete-task-modal', { subtask: this.task })
},
filesUploaded(files) {
this.task.files = files
},
@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.33329 13.3334V13.8334C5.4659 13.8334 5.59308 13.7807 5.68685 13.6869L5.33329 13.3334ZM2.66663 13.3334H2.16663C2.16663 13.6095 2.39048 13.8334 2.66663 13.8334V13.3334ZM2.66663 10.6667L2.31307 10.3132C2.2193 10.4069 2.16663 10.5341 2.16663 10.6667H2.66663ZM10.1952 3.13813L10.5488 3.49169V3.49169L10.1952 3.13813ZM11.138 3.13813L10.7845 3.49169V3.49169L11.138 3.13813ZM12.8619 4.86199L13.2154 4.50844V4.50844L12.8619 4.86199ZM12.8619 5.8048L12.5083 5.45125L12.8619 5.8048ZM5.33329 12.8334H2.66663V13.8334H5.33329V12.8334ZM3.16663 13.3334V10.6667H2.16663V13.3334H3.16663ZM3.02018 11.0203L10.5488 3.49169L9.84167 2.78458L2.31307 10.3132L3.02018 11.0203ZM10.7845 3.49169L12.5083 5.21554L13.2154 4.50844L11.4916 2.78458L10.7845 3.49169ZM12.5083 5.45125L4.97974 12.9798L5.68685 13.6869L13.2154 6.15835L12.5083 5.45125ZM12.5083 5.21554C12.5734 5.28063 12.5734 5.38616 12.5083 5.45125L13.2154 6.15835C13.6711 5.70274 13.6711 4.96405 13.2154 4.50844L12.5083 5.21554ZM10.5488 3.49169C10.6139 3.4266 10.7194 3.4266 10.7845 3.49169L11.4916 2.78458C11.036 2.32897 10.2973 2.32897 9.84167 2.78458L10.5488 3.49169Z" fill="#14181F"/>
<path d="M8 5.33325L10.6667 7.99992" stroke="#14181F" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

@@ -1,7 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.33337 6.66675L9.33337 11.3334" stroke="#14181F" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.66663 6.66675L6.66663 11.3334" stroke="#14181F" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4 4V3.5C3.72386 3.5 3.5 3.72386 3.5 4H4ZM12 4H12.5C12.5 3.72386 12.2761 3.5 12 3.5V4ZM4 4.5H12V3.5H4V4.5ZM11.5 4V13.3333H12.5V4H11.5ZM11.3333 13.5H4.66667V14.5H11.3333V13.5ZM4.5 13.3333V4H3.5V13.3333H4.5ZM4.66667 13.5C4.57462 13.5 4.5 13.4254 4.5 13.3333H3.5C3.5 13.9777 4.02233 14.5 4.66667 14.5V13.5ZM11.5 13.3333C11.5 13.4254 11.4254 13.5 11.3333 13.5V14.5C11.9777 14.5 12.5 13.9777 12.5 13.3333H11.5Z" fill="#14181F"/>
<path d="M2.66663 4H13.3333" stroke="#14181F" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.6667 4V4.5C10.9429 4.5 11.1667 4.27614 11.1667 4H10.6667ZM5.33337 4H4.83337C4.83337 4.27614 5.05723 4.5 5.33337 4.5V4ZM6.00004 2.5H10V1.5H6.00004V2.5ZM10.1667 2.66667V4H11.1667V2.66667H10.1667ZM10.6667 3.5H5.33337V4.5H10.6667V3.5ZM5.83337 4V2.66667H4.83337V4H5.83337ZM10 2.5C10.0921 2.5 10.1667 2.57462 10.1667 2.66667H11.1667C11.1667 2.02233 10.6444 1.5 10 1.5V2.5ZM6.00004 1.5C5.35571 1.5 4.83337 2.02233 4.83337 2.66667H5.83337C5.83337 2.57462 5.90799 2.5 6.00004 2.5V1.5Z" fill="#14181F"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

@@ -13,13 +13,14 @@
<tbody>
<tr class="cursor-pointer" v-for="task in tasks" :key="task.id" @click.stop="editTask(task, false)">
<td>{{ task.project_code }}</td>
<td>{{ task.master_task }}</td>
<td>{{ task.master_task?.name || task.master_task }}</td>
<td>{{ task.duration }} h</td>
<td>{{ task.duration - task.spent_time }} h</td>
<td class="task-action">
<div class="d-flex justify-start">
<img class="pencil-icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon" @click.stop="editTask(task, true)" />
<img class="trash-icon" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon" @click.stop="deleteTask(task)" />
<img class="pencil-icon mr-3" :src="require('@/plugins/app/_img/icons/eye.svg')" alt="pencil-icon" @click.stop="editTask(task, false)">
<img class="pencil-icon" :src="require('@/plugins/app/_img/icons/pencil.svg')" alt="pencil-icon" @click.stop="editTask(task, true)" />
<img class="trash-icon" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="deleteTask(task)" />
</div>
</td>
</tr>
@@ -39,7 +39,7 @@ export default {
return null
return this.ongoingSubtasks.filter(subtask => {
return this.filterParams(this.searchQuery, subtask.master_task) || this.filterParams(this.searchQuery, subtask.project_code)
return this.filterParams(this.searchQuery, subtask.master_task?.name || subtask.master_task) || this.filterParams(this.searchQuery, subtask.project_code)
})
}
},
@@ -13,12 +13,13 @@
<tr class="cursor-pointer" v-for="task in tasks" :key="task.id" @click.stop="editTask(task, false)">
<td>{{ task.project_code }}</td>
<td>{{ task.master_task }}</td>
<td>{{ task.master_task?.name || task.master_task }}</td>
<td>{{ task.spent_time }} h</td>
<td class="task-action">
<div class="d-flex justify-start">
<img class="pencil-icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon" @click.stop="editTask(task, true)">
<img class="trash-icon" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon" @click.stop="deleteTask(task)">
<img class="pencil-icon mr-3" :src="require('@/plugins/app/_img/icons/eye.svg')" alt="pencil-icon" @click.stop="editTask(task, false)">
<img class="pencil-icon" :src="require('@/plugins/app/_img/icons/pencil.svg')" alt="pencil-icon" @click.stop="editTask(task, true)">
<img class="trash-icon" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="deleteTask(task)">
</div>
</td>
</tr>
@@ -39,7 +39,7 @@ export default {
return null
return this.unscheduledSubtasks.filter(subtask => {
return this.filterParams(this.searchQuery, subtask.master_task) || this.filterParams(this.searchQuery, subtask.project_code)
return this.filterParams(this.searchQuery, subtask.master_task?.name || subtask.master_task) || this.filterParams(this.searchQuery, subtask.project_code)
})
}
},
@@ -13,8 +13,8 @@
<td>{{ team.name }}</td>
<td class="task-action">
<div class="d-flex justify-start">
<img class="pencil-icon" :src="require('@/plugins/tm@overview/_img/pencil-icon.svg')" alt="pencil-icon" @click.stop="editTeam(team)" />
<img class="trash-icon" :src="require('@/plugins/tm@overview/_img/trash-icon.svg')" alt="trash-icon" @click.stop="deleteTeam(team)" />
<img class="pencil-icon" :src="require('@/plugins/app/_img/icons/pencil.svg')" alt="pencil-icon" @click.stop="editTeam(team)" />
<img class="trash-icon" :src="require('@/plugins/app/_img/icons/bin.svg')" alt="trash-icon" @click.stop="deleteTeam(team)" />
</div>
</td>
</tr>
+2 -2
View File
@@ -1,5 +1,5 @@
import axios from '@/plugins/w/axios/models/axios'
import './refreshExpired'
// import './refreshExpired'
export default {
namespaced: true,
@@ -35,7 +35,7 @@ export default {
actions: {
login({commit}: {commit: any}, credentials: any) {
return new Promise((resolve, reject) => {
axios.post('v1/tokens/create', credentials)
axios.post('v1/tokens/create', {data: credentials})
.then((response: any) => {
console.log(response)
const token = response.token