mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 14:29:34 +00:00
[Projects overview] Added filter logics and prepared for BE
This commit is contained in:
1 parent
d7b26d731a
commit
4cd1504343
12 files changed
+1688
-198
No files matched your search
+1
-1
@@ -19,11 +19,11 @@
|
||||
"@vuelidate/validators": "^2.0.0",
|
||||
"@vuepic/vue-datepicker": "^3.6.0",
|
||||
"@vueup/vue-quill": "^1.0.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"axios": "^1.1.3",
|
||||
"axios-auth-refresh": "^3.3.4",
|
||||
"core-js": "^3.8.3",
|
||||
"date-fns": "^2.29.3",
|
||||
"file-saver": "^2.0.5",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mitt": "^2.1.0",
|
||||
"moment": "^2.29.4",
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Master task 1",
|
||||
"starts_at": "2023-01-01",
|
||||
"deadline": "2023-01-09",
|
||||
"is_finished": true,
|
||||
"project_code": "CO-2201",
|
||||
"color": "#BB86FC"
|
||||
},
|
||||
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Master task 2",
|
||||
"starts_at": "2023-01-02",
|
||||
"deadline": "2023-01-05",
|
||||
"is_finished": false,
|
||||
"project_code": "CO-2201",
|
||||
"color": "#FF7B5E"
|
||||
},
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Master task 3",
|
||||
"starts_at": "2023-01-12",
|
||||
"deadline": "2023-01-15",
|
||||
"is_finished": false,
|
||||
"project_code": "CO-2201",
|
||||
"color": "#011995"
|
||||
},
|
||||
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Master task 4",
|
||||
"starts_at": "2023-01-12",
|
||||
"deadline": "2023-02-12",
|
||||
"is_finished": false,
|
||||
"project_code": "CO-2201",
|
||||
"color": "#BABE00"
|
||||
}
|
||||
],
|
||||
"status": 200
|
||||
}
|
||||
@@ -48,7 +48,7 @@ const options: Options = {
|
||||
'POST v1/auth/post': true,
|
||||
|
||||
'GET v1/master-tasks/(id)': true,
|
||||
// 'GET v1/master-tasks': true,
|
||||
'GET v1/master-tasks': true,
|
||||
'POST v1/master-tasks/(id)': true,
|
||||
'DELETE v1/master-tasks/(id)': true,
|
||||
'POST v1/master-tasks': true,
|
||||
|
||||
@@ -179,9 +179,9 @@ export default {
|
||||
|
||||
taskClicked(task) {
|
||||
if (task.nonWorking) return
|
||||
console.log("task", task)
|
||||
// console.log("task", task)
|
||||
if (task.end.getTime() - task.start.getTime() <= 3600000) {
|
||||
console.log("ShortTask")
|
||||
// console.log("ShortTask")
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
<template>
|
||||
<div id="calendar" class="mb-12">
|
||||
<V-full-calendar ref="fullCalendar" :options="calendarOptions" />
|
||||
<!-- <Z-master-task-modal ref="z-master-task-modal" /> -->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import VFullCalendar from '@fullcalendar/vue3'
|
||||
import dayGridPlugin from '@fullcalendar/daygrid'
|
||||
// import ZMasterTaskModal from '@/plugins/tm@modal/master-task/z-master-task-modal.vue'
|
||||
|
||||
export default {
|
||||
emits: ['open-detail'],
|
||||
|
||||
components: {
|
||||
VFullCalendar,
|
||||
// ZMasterTaskModal
|
||||
VFullCalendar
|
||||
},
|
||||
|
||||
props: {
|
||||
@@ -39,9 +38,7 @@ export default {
|
||||
eventContent: (eventInfo) => {
|
||||
return { html: eventInfo.event.extendedProps.title_html }
|
||||
},
|
||||
eventClick: (info) => {
|
||||
return this.editTask(info.event._def.publicId, false)
|
||||
}
|
||||
eventClick: (info) => this.$emit('open-detail', info.event._def.publicId)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -52,12 +49,6 @@ export default {
|
||||
this.$refs.fullCalendar?.getApi().gotoDate(new Date(currentYear, this.month, 1))
|
||||
},
|
||||
|
||||
methods: {
|
||||
editTask(masterTask, editMode) {
|
||||
this.$events.emit('show-master-task-modal', {masterTask, editMode})
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
month(selectedMonth) {
|
||||
const currentYear = new Date().getFullYear()
|
||||
@@ -109,4 +100,6 @@ export default {
|
||||
border: none
|
||||
top: 2px
|
||||
right: 4px
|
||||
&:deep(.fc-daygrid-day-frame)
|
||||
min-height: 100px
|
||||
</style>
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<v-row class="px-10 py-8 subheader">
|
||||
<v-select v-model="filter.selectedProject" class="subheader-input" :items="projects" label="Projekt" variant="outlined"></v-select>
|
||||
<v-select v-model="filter.selectedProject" class="subheader-input" :items="[null, projects]" label="Projekt" variant="outlined" :disabled="true" />
|
||||
|
||||
<v-select v-model="filter.selectedTeam" class="subheader-input" :items="teams" label="Tím" variant="outlined"></v-select>
|
||||
<v-select v-model="filter.selectedTeam" class="subheader-input" :items="[null, ...teams]" label="Tím" variant="outlined" item-title="name" item-value="id" />
|
||||
|
||||
<v-select v-model="filter.selectedEmployee" class="subheader-input" :items="employees" label="Zamestnanec" variant="outlined"></v-select>
|
||||
<v-select v-model="filter.selectedEmployee" class="subheader-input" :items="[null, ...enrichedEmployees]" label="Zamestnanec" variant="outlined" item-title="_fullName" item-value="id" />
|
||||
|
||||
<v-select v-model="filter.selectedMonth" class="subheader-input" :items="months" label="Mesiac" variant="outlined"></v-select>
|
||||
<v-select v-model="filter.selectedMonth" class="subheader-input" :items="months" label="Mesiac" variant="outlined" />
|
||||
|
||||
<div class="subheader-input switch">
|
||||
<p class="switch-label">Zobraziť ukončené</p>
|
||||
@@ -19,7 +19,22 @@
|
||||
export default {
|
||||
emits: ['filterChanged'],
|
||||
|
||||
props: ['projects', 'teams', 'employees'],
|
||||
props: {
|
||||
projects: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
|
||||
teams: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
|
||||
employees: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
@@ -37,6 +52,7 @@ export default {
|
||||
{ title: 'November', value: 10 },
|
||||
{ title: 'December', value: 11 }
|
||||
],
|
||||
|
||||
filter: {
|
||||
selectedProject: null,
|
||||
selectedTeam: null,
|
||||
@@ -47,6 +63,17 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
enrichedEmployees() {
|
||||
const employees = this.employees
|
||||
|
||||
return employees.map(employee => {
|
||||
employee._fullName = `${employee.name} ${employee.surname}`
|
||||
return employee
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
filter: {
|
||||
handler() {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<W-loadable :content="events" empty-message="Nepodarilo sa nacitat data!">
|
||||
<A-project-filter :projects="projects" @filterChanged="onFilterChanged" />
|
||||
<A-project-calendar :events="filteredEvents" :month="filterSettings.selectedMonth" />
|
||||
<W-loadable :content="masterTasks" empty-message="Nepodarilo sa nacitat data!">
|
||||
<A-project-filter :projects="projects" :teams="teams" :employees="employees" @filterChanged="onFilterChanged" />
|
||||
<A-project-calendar :events="filteredEvents" :month="filter.selectedMonth" @open-detail="openMasterTaskModal" />
|
||||
</W-loadable>
|
||||
</div>
|
||||
</template>
|
||||
@@ -10,6 +10,7 @@
|
||||
<script>
|
||||
import AProjectCalendar from './_components/a-project-calendar.vue'
|
||||
import AProjectFilter from './_components/a-project-filter.vue'
|
||||
import moment from 'moment'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -18,47 +19,96 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filterSettings: {
|
||||
selectedEmployee: null,
|
||||
selectedMonth: new Date().getMonth(),
|
||||
selectedProject: null,
|
||||
selectedTeam: null,
|
||||
showFinishedTasks: false
|
||||
},
|
||||
// Kravarik: Toto je preco hardcodenute?
|
||||
projects: ['Projekt1', 'Projekt2', 'Projekt3', 'Projekt4'],
|
||||
masterTasks: null,
|
||||
teams: null,
|
||||
employees: null,
|
||||
selectedProject: null,
|
||||
events: [],
|
||||
filteredEvents: []
|
||||
filter: {
|
||||
selectedMonth: new Date().getMonth()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
filteredEvents() {
|
||||
if (!this.masterTasks || this.masterTasks.error)
|
||||
return []
|
||||
|
||||
// duplicate all tasks
|
||||
let events = this.masterTasks
|
||||
|
||||
// show/hide finished tasks
|
||||
if (!this.filter.showFinishedTasks)
|
||||
events = events.filter(event => !event.is_finished)
|
||||
|
||||
// filter by team_id
|
||||
if (this.filter.selectedTeam)
|
||||
events = events.filter(event => event.team_id == this.filter.selectedTeam)
|
||||
|
||||
// filter by employee_id
|
||||
if (this.filter.selectedEmployee)
|
||||
events = events.filter(event => event.employees.find(employee => employee.id == this.filter.selectedEmployee))
|
||||
|
||||
// format masterTasks to event format for calendar
|
||||
events = events.map(event => {
|
||||
const color = this._stringToHexColor(`${event.project_code}${event.name}`)
|
||||
|
||||
return {
|
||||
id: event.id,
|
||||
title: `${event.project_code} - ${event.name}`,
|
||||
title_html: `${event.project_code} - <b>${event.name}</b>`,
|
||||
start: new Date(event.starts_at),
|
||||
end: new Date(event.deadline),
|
||||
is_finished: event.is_finished,
|
||||
project_code: event.project_code,
|
||||
backgroundColor: `${color}CC`,
|
||||
borderColor: color
|
||||
}
|
||||
})
|
||||
|
||||
return events
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this._getData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
async _getData() {
|
||||
try {
|
||||
const events = await this.$axios.get_auth_data('v1/overview/projects')
|
||||
this.events = events.map((item) => ({
|
||||
id: item.id,
|
||||
title: `${item.project_code} - ${item.name}`,
|
||||
title_html: `${item.project_code} - <b>${item.name}</b>`,
|
||||
start: item.starts_at,
|
||||
end: item.deadline,
|
||||
is_finished: item.is_finished,
|
||||
project_code: item.project_code,
|
||||
backgroundColor: item.color,
|
||||
borderColor: item.color
|
||||
}))
|
||||
this.filteredEvents = this.events.filter((item) => !item.is_finished)
|
||||
this.teams = await this.$axios.get_auth_data('v1/teams')
|
||||
this.employees = await this.$axios.get_auth_data('v1/employees')
|
||||
this.masterTasks = await this.$axios.get_auth_data('v1/master-tasks')
|
||||
} catch (error) {
|
||||
this.$toast.error(error)
|
||||
this.masterTasks = {error}
|
||||
}
|
||||
},
|
||||
|
||||
onFilterChanged(filterValues) {
|
||||
this.filter = filterValues
|
||||
this.filteredEvents = this.events.filter((item) => this.filter.showFinishedTasks || item.is_finished == false)
|
||||
},
|
||||
|
||||
openMasterTaskModal(masterTaskId) {
|
||||
const masterTask = this.masterTasks.find(masterTask => masterTask.id == masterTaskId)
|
||||
this.$events.emit('show-master-task-modal', {masterTask, editMode: false})
|
||||
},
|
||||
|
||||
_stringToHexColor(string) {
|
||||
let hash = 0;
|
||||
|
||||
for (let i = 0; i < string.length; i++) {
|
||||
hash = string.charCodeAt(i) + ((hash << 5) - hash);
|
||||
}
|
||||
|
||||
let color = '#';
|
||||
for (let i = 0; i < 3; i++) {
|
||||
let value = (hash >> (i * 8)) & 0xFF;
|
||||
color += ('00' + value.toString(16)).substr(-2);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ export default {
|
||||
},
|
||||
|
||||
async onEventMoved(event) {
|
||||
console.log("drag", event)
|
||||
// console.log("drag", event)
|
||||
const task = this.timelineData.tasks.find(task => task.id == event.event.id)
|
||||
|
||||
try {
|
||||
@@ -138,7 +138,7 @@ export default {
|
||||
task.split = event.newSplit
|
||||
} catch(error) {
|
||||
this.$toast.error(error)
|
||||
|
||||
|
||||
task.start = new Date(event.originalEvent.start)
|
||||
task.end = new Date(event.originalEvent.end)
|
||||
task.split = event.oldSplit
|
||||
|
||||
@@ -56,7 +56,7 @@ export default {
|
||||
this.timelineData[i].splitId = i + 1
|
||||
this.splitDays.push({
|
||||
id: i + 1,
|
||||
employeeId: this.timelineData[i].id,
|
||||
employeeId: this.timelineData[i].id,
|
||||
firstName: this.timelineData[i].name,
|
||||
name: this.timelineData[i].name + " " + this.timelineData[i].surname,
|
||||
initials: this.timelineData[i].name.charAt(0).toUpperCase() + this.timelineData[i].surname.charAt(0).toUpperCase(),
|
||||
@@ -121,7 +121,7 @@ export default {
|
||||
},
|
||||
|
||||
async onEventMoved(event) {
|
||||
console.log("drag", event)
|
||||
// console.log("drag", event)
|
||||
const task = this.timelineData.tasks.find(task => task.id == event.event.id)
|
||||
const newEmployeeId = this.splitDays.find(split => split.id == event.newSplit).employeeId
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ export default {
|
||||
state.user = data.user
|
||||
localStorage.setItem('wzo_vue_user_user', JSON.stringify(data.user))
|
||||
}
|
||||
|
||||
console.log(state)
|
||||
},
|
||||
auth_error(state: any) {
|
||||
state.token = ''
|
||||
|
||||
@@ -42,11 +42,8 @@ export default {
|
||||
|
||||
watch: {
|
||||
content(value) {
|
||||
console.log(`XX: ${value}`)
|
||||
|
||||
if (value) {
|
||||
this._stopLoading()
|
||||
console.log(' STOP LOADING')
|
||||
}
|
||||
else
|
||||
this._startLoading()
|
||||
|
||||
Reference in new issue
Block a user