[CR] sorting v-select, [bugy]

This commit is contained in:
romankko2 committed 2023-09-15 17:24:53 +02:00
1 parent 7c94f4c576
commit 4ed354904c
16 files changed
+195 -23

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+1
View File
@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" /> <link rel="icon" href="<%= BASE_URL %>favicon/favicon.ico" />
<title>ToDo by JANDL</title> <title>ToDo by JANDL</title>
</head> </head>
<body> <body>
@@ -182,8 +182,10 @@ export default {
const date = addDays(this.calConfig.date, newSplit - 1) const date = addDays(this.calConfig.date, newSplit - 1)
const start = date.setHours(Math.round(event.startTimeMinutes / 60), Math.round(event.startTimeMinutes % 60), 0) const start = date.setHours(Math.round(event.startTimeMinutes / 60), Math.round(event.startTimeMinutes % 60), 0)
const end = date.setHours(Math.round(event.endTimeMinutes / 60), Math.round(event.endTimeMinutes % 60), 0) const end = date.setHours(Math.round(event.endTimeMinutes / 60), Math.round(event.endTimeMinutes % 60), 0)
const editedSubtask = { const split = this.splits.find(split => split.id == newSplit )
if(this.$route.name == 'Dashboard - Tasks') {
const editedSubtask = {
...event.subtask, ...event.subtask,
timeblocks: [...event.subtask.timeblocks, { timeblocks: [...event.subtask.timeblocks, {
id: event._timeblock_id, id: event._timeblock_id,
@@ -196,7 +198,6 @@ export default {
return timesheet return timesheet
}) })
} }
try { try {
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${editedSubtask.id}`, editedSubtask) const { subtask } = await this.$axios.put_auth(`v1/subtasks/${editedSubtask.id}`, editedSubtask)
this.$events.emit('on-subtask-edited', subtask) this.$events.emit('on-subtask-edited', subtask)
@@ -206,6 +207,28 @@ export default {
} catch (error) { } catch (error) {
this.$toast.error(error.message || error) this.$toast.error(error.message || error)
} }
} else if(this.$route.name == 'Dashboard - Teams') {
const editedSubtask = {
...event.subtask,
employee_id: split.employee_id,
timeblocks: [...event.subtask.timeblocks, {
id: event._timeblock_id,
is_finished: 0,
start: tmUtils.formatDateTimeForBackend(event.start),
end: tmUtils.formatDateTimeForBackend(event.end)
}],
timesheets: event.subtask.timesheets.map((timesheet) => {
delete timesheet.employee_name
return timesheet
})
}
try {
const { subtask } = await this.$axios.put_auth(`v1/subtasks/${editedSubtask.id}`, editedSubtask)
this.$events.emit('on-subtask-edited', subtask)
} catch (error) {
this.$toast.error(error.message || error)
}
}
}, },
onReady() { onReady() {
@@ -56,6 +56,7 @@ export default {
days.push({ days.push({
id: index + 1, id: index + 1,
name: employee.name, name: employee.name,
employee_id: employee.id,
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: unscheduledTime > 0 ? (unscheduledTime / 60).toFixed(1) : 0, unscheduledTime: unscheduledTime > 0 ? (unscheduledTime / 60).toFixed(1) : 0,
@@ -8,8 +8,8 @@
:items="enrichedEmployees" :items="enrichedEmployees"
item-title="_fullName" item-title="_fullName"
item-value="id" item-value="id"
:disabled="isSortingActive"
/> />
<v-text-field <v-text-field
v-model="searchQuery" v-model="searchQuery"
class="subheader-input" class="subheader-input"
@@ -18,22 +18,33 @@
prepend-inner-icon="mdi-magnify" prepend-inner-icon="mdi-magnify"
@input="onInput" @input="onInput"
type="text" type="text"
:disabled="isSortingActive"
></v-text-field> ></v-text-field>
<v-select
v-model="sortOrder"
class="subheader-input"
:items="sortOptions"
variant="outlined"
label="Zoradiť podľa"
item-title="text"
item-value="value"
></v-select>
</v-row> </v-row>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import AutocompleteMixin from '@/plugins/tm@_mixins/autocomplete.mixin' import AutocompleteMixin from '@/plugins/tm@_mixins/autocomplete.mixin'
export default { export default {
mixins: [AutocompleteMixin], mixins: [AutocompleteMixin],
emits: ['search', 'employee-selected'], emits: ['search', 'employee-selected', 'update-sort-order'],
data() { data() {
return { return {
selectedEmployeeId: null, selectedEmployeeId: null,
searchQuery: '' searchQuery: '',
sortOrder: null
} }
}, },
@@ -43,17 +54,39 @@ export default {
computed: { computed: {
...mapGetters('tm', ['enrichedEmployees']), ...mapGetters('tm', ['enrichedEmployees']),
sortOptions() {
return [
{ text: 'Zrušiť filter', value: null },
{ text: 'Názov (A-Z)', value: 'nameAsc' },
{ text: 'Názov (Z-A)', value: 'nameDesc' },
{ text: 'Dátum (Najnovší - Najstarší)', value: 'deadlineDesc' },
{ text: 'Dátum (Najstarší - Najnovší)', value: 'deadlineAsc' }
]
},
isSortingActive() {
return this.sortOrder !== null && this.sortOrder !== 'null'
},
}, },
methods: { methods: {
onInput() { onInput() {
this.$emit('search', this.searchQuery) this.$emit('search', this.searchQuery)
},
updateSortOrder() {
this.$emit('update-sort-order', this.sortOrder)
} }
}, },
watch: { watch: {
selectedEmployeeId() { selectedEmployeeId() {
this.$emit('employee-selected', this.selectedEmployeeId) this.$emit('employee-selected', this.selectedEmployeeId)
},
sortOrder() {
this.updateSortOrder()
} }
} }
} }
@@ -92,4 +125,11 @@ export default {
max-width: 100% !important max-width: 100% !important
min-width: 100% min-width: 100%
margin-bottom: 15px margin-bottom: 15px
:deep(.v-select__selection-text)
display: -webkit-box
-webkit-line-clamp: 1
-webkit-box-orient: vertical
overflow: hidden
text-overflow: ellipsis
</style> </style>
@@ -15,7 +15,7 @@
<tbody> <tbody>
<tr class="cursor-pointer" v-for="subtask in subtasks" :key="subtask.id" @click.stop="editTask(subtask, false)"> <tr class="cursor-pointer" v-for="subtask in subtasks" :key="subtask.id" @click.stop="editTask(subtask, false)">
<td>{{ subtask.project_code }}</td> <td>{{ subtask.project_code }}</td>
<td>{{ subtask.title ?? subtask.master_task?.name ?? subtask.master_task }}</td> <td>{{ subtask.title ?? subtask.master_task }}</td>
<td v-if="subtask.deadline">{{ getDeadline(subtask) }}</td> <td v-if="subtask.deadline">{{ getDeadline(subtask) }}</td>
<v-tooltip text="Deadline z Mastertasku" location="end"> <v-tooltip text="Deadline z Mastertasku" location="end">
<template v-slot:activator="{ props }"> <template v-slot:activator="{ props }">
@@ -1,10 +1,10 @@
<template> <template>
<div> <div>
<Z-tasks-search @search="onSearch" @employee-selected="onEmployeeSelected" /> <Z-tasks-search @search="onSearch" @employee-selected="onEmployeeSelected" @update-sort-order="onUpdateSortOrder" />
<W-loadable :content="filteredOngoingTasks" :emptyMessage="searchQuery.length ? 'Neboli nájdené žiadne úlohy' : 'Nenašli sa žiadne záznamy'"> <W-loadable :content="filteredOngoingTasks" :emptyMessage="searchQuery.length ? 'Neboli nájdené žiadne úlohy' : 'Nenašli sa žiadne záznamy'">
<A-ongoing-table :subtasks="filteredOngoingTasks" /> <A-ongoing-table :subtasks="selectedTasks" />
</W-loadable> </W-loadable>
</div> </div>
@@ -23,7 +23,8 @@ export default {
data() { data() {
return { return {
searchQuery: '' searchQuery: '',
sortOrder: null
} }
}, },
@@ -32,15 +33,58 @@ export default {
}, },
computed: { computed: {
...mapGetters('tm', ['ongoingSubtasks']), ...mapGetters('tm', ['ongoingSubtasks', 'mastertasks']),
filteredOngoingTasks() { filteredOngoingTasks() {
if (!this.ongoingSubtasks) if (!this.ongoingSubtasks)
return null return null
return this.ongoingSubtasks.filter(subtask => { return this.ongoingSubtasks.filter(subtask => {
return this.filterParams(this.searchQuery, subtask.master_task?.name || subtask.master_task) || this.filterParams(this.searchQuery, subtask.project_code) return this.filterParams(this.searchQuery, subtask.master_task?.name || subtask.title) || this.filterParams(this.searchQuery, subtask.project_code)
}) })
},
sortedOngoingTasks() {
if (!this.ongoingSubtasks)
return null
let sortedTasks = this.ongoingSubtasks
//Sorting by name A-Z
if (this.sortOrder === 'nameAsc') {
sortedTasks.sort((a, b) => {
const nameA = (a.title || a.master_task || '').toLowerCase()
const nameB = (b.title || b.master_task || '').toLowerCase()
return nameA.localeCompare(nameB)
})
//Sorting by name Z-A
} else if (this.sortOrder === 'nameDesc') {
sortedTasks.sort((a, b) => {
const nameA = (a.title || a.master_task || '').toLowerCase()
const nameB = (b.title || b.master_task || '').toLowerCase()
return nameB.localeCompare(nameA)
})
//Sorting by date Newest-Oldest
} else if (this.sortOrder === 'deadlineDesc') {
sortedTasks.sort((a, b) => {
const deadlineA = a.deadline ? new Date(a.deadline) : new Date(this.getMasterTaskDeadline(a))
const deadlineB = b.deadline ? new Date(b.deadline) : new Date(this.getMasterTaskDeadline(b))
return deadlineB - deadlineA
})
//Sorting by date Oldest-Newest
} else if (this.sortOrder === 'deadlineAsc') {
sortedTasks.sort((a, b) => {
const deadlineA = a.deadline ? new Date(a.deadline) : new Date(this.getMasterTaskDeadline(a))
const deadlineB = b.deadline ? new Date(b.deadline) : new Date(this.getMasterTaskDeadline(b))
return deadlineA - deadlineB
})
}
return sortedTasks
},
selectedTasks() {
return this.sortOrder ? this.sortedOngoingTasks : this.filteredOngoingTasks
} }
}, },
@@ -53,9 +97,19 @@ export default {
this.$store.dispatch('tm/loadOngoingSubtasks', id) this.$store.dispatch('tm/loadOngoingSubtasks', id)
}, },
onUpdateSortOrder(newSortOrder) {
this.sortOrder = newSortOrder
},
filterParams(searchQuery, row) { filterParams(searchQuery, row) {
if(!row) return false if(!row) return false
return row.toLowerCase().includes(searchQuery.toLowerCase()) return row.toLowerCase().includes(searchQuery.toLowerCase())
},
getMasterTaskDeadline(subtask) {
if(!this.mastertasks) return ''
const masterTask = this.mastertasks.find((mt) => mt.id === subtask.master_task_id)
return masterTask ? masterTask.deadline : ''
} }
} }
} }
@@ -14,7 +14,7 @@
<tr class="cursor-pointer" v-for="subtask in subtasks" :key="subtask.id" @click.stop="editTask(subtask, false)"> <tr class="cursor-pointer" v-for="subtask in subtasks" :key="subtask.id" @click.stop="editTask(subtask, false)">
<td>{{ subtask.project_code }}</td> <td>{{ subtask.project_code }}</td>
<td>{{ subtask.title ?? subtask.master_task?.name ?? subtask.master_task }}</td> <td>{{ subtask.title ?? subtask.master_task }}</td>
<td v-if="subtask?.deadline">{{ getDeadline(subtask) }}</td> <td v-if="subtask?.deadline">{{ getDeadline(subtask) }}</td>
<v-tooltip text="Deadline z Mastertasku" location="end"> <v-tooltip text="Deadline z Mastertasku" location="end">
<template v-slot:activator="{ props }"> <template v-slot:activator="{ props }">
@@ -1,10 +1,10 @@
<template> <template>
<div> <div>
<Z-tasks-search @search="onSearch" @employee-selected="onEmployeeSelected" /> <Z-tasks-search @search="onSearch" @employee-selected="onEmployeeSelected" @update-sort-order="onUpdateSortOrder" />
<W-loadable :content="filteredUnscheduledTasks" :emptyMessage="searchQuery.length ? 'Neboli nájdené žiadne úlohy' : 'Nenašli sa žiadne záznamy'"> <W-loadable :content="filteredUnscheduledTasks" :emptyMessage="searchQuery.length ? 'Neboli nájdené žiadne úlohy' : 'Nenašli sa žiadne záznamy'">
<A-unscheduled-table :subtasks="filteredUnscheduledTasks" /> <A-unscheduled-table :subtasks="selectedTasks" />
</W-loadable> </W-loadable>
</div> </div>
@@ -23,7 +23,8 @@ export default {
data() { data() {
return { return {
searchQuery: '' searchQuery: '',
sortOrder: null
} }
}, },
@@ -32,15 +33,57 @@ export default {
}, },
computed: { computed: {
...mapGetters('tm', ['unscheduledSubtasks']), ...mapGetters('tm', ['unscheduledSubtasks', 'mastertasks']),
filteredUnscheduledTasks() { filteredUnscheduledTasks() {
if (!this.unscheduledSubtasks) if (!this.unscheduledSubtasks)
return null return null
return this.unscheduledSubtasks.filter(subtask => { return this.unscheduledSubtasks.filter(subtask => {
return this.filterParams(this.searchQuery, subtask.master_task?.name || subtask.master_task) || this.filterParams(this.searchQuery, subtask.project_code) return this.filterParams(this.searchQuery, subtask.master_task?.name || subtask.title) || this.filterParams(this.searchQuery, subtask.project_code)
}) })
},
sortedUnscheduledTasks() {
if (!this.unscheduledSubtasks)
return null
let sortedTasks = this.unscheduledSubtasks
//Sorting by name A-Z
if (this.sortOrder === 'nameAsc') {
sortedTasks.sort((a, b) => {
const nameA = (a.title || a.master_task || '').toLowerCase()
const nameB = (b.title || b.master_task || '').toLowerCase()
return nameA.localeCompare(nameB)
})
//Sorting by name Z-A
} else if (this.sortOrder === 'nameDesc') {
sortedTasks.sort((a, b) => {
const nameA = (a.title || a.master_task || '').toLowerCase()
const nameB = (b.title || b.master_task || '').toLowerCase()
return nameB.localeCompare(nameA)
})
//Sorting by date Newest-Oldest
} else if (this.sortOrder === 'deadlineDesc') {
sortedTasks.sort((a, b) => {
const deadlineA = a.deadline ? new Date(a.deadline) : new Date(this.getMasterTaskDeadline(a))
const deadlineB = b.deadline ? new Date(b.deadline) : new Date(this.getMasterTaskDeadline(b))
return deadlineB - deadlineA
})
//Sorting by date Oldest-Newest
} else if (this.sortOrder === 'deadlineAsc') {
sortedTasks.sort((a, b) => {
const deadlineA = a.deadline ? new Date(a.deadline) : new Date(this.getMasterTaskDeadline(a))
const deadlineB = b.deadline ? new Date(b.deadline) : new Date(this.getMasterTaskDeadline(b))
return deadlineA - deadlineB
})
}
return sortedTasks
},
selectedTasks() {
return this.sortOrder ? this.sortedUnscheduledTasks : this.filteredUnscheduledTasks
} }
}, },
@@ -53,9 +96,19 @@ export default {
this.$store.dispatch('tm/loadUnscheduledSubtasks', id) this.$store.dispatch('tm/loadUnscheduledSubtasks', id)
}, },
onUpdateSortOrder(newSortOrder) {
this.sortOrder = newSortOrder
},
filterParams(searchQuery, row) { filterParams(searchQuery, row) {
if(!row) return false if(!row) return false
return row.toLowerCase().includes(searchQuery.toLowerCase()) return row.toLowerCase().includes(searchQuery.toLowerCase())
},
getMasterTaskDeadline(subtask) {
if(!this.mastertasks) return ''
const masterTask = this.mastertasks.find((mt) => mt.id === subtask.master_task_id)
return masterTask ? masterTask.deadline : ''
} }
} }
} }