From 0f946e95140d2b902bd476c0ed165a6cd9219fb7 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Fri, 22 May 2026 13:48:43 +0200 Subject: [PATCH] feat: Optimize activity ordering and enhance plan item movement functionality --- backend/services/diaryDateActivityService.js | 25 ++---- frontend/src/views/DiaryView.vue | 80 +++++++++++++++++++- 2 files changed, 86 insertions(+), 19 deletions(-) diff --git a/backend/services/diaryDateActivityService.js b/backend/services/diaryDateActivityService.js index 5056b67b..78f4f07f 100644 --- a/backend/services/diaryDateActivityService.js +++ b/backend/services/diaryDateActivityService.js @@ -64,17 +64,8 @@ class DiaryDateActivityService { } } - const maxOrderWhere = restData.groupId - ? { - diaryDateId: data.diaryDateId, - groupId: restData.groupId - } - : { - // Globale Aktivitäten bei "Alle" sollen am Ende des gesamten Tagesplans landen. - diaryDateId: data.diaryDateId - }; const maxOrderId = await DiaryDateActivity.max('orderId', { - where: maxOrderWhere + where: { diaryDateId: data.diaryDateId } }); const newOrderId = maxOrderId !== null ? maxOrderId + 1 : 1; restData.orderId = newOrderId; @@ -125,6 +116,12 @@ class DiaryDateActivityService { } } + for (const key of Object.keys(data)) { + if (data[key] === undefined) { + delete data[key]; + } + } + return await activity.update(data); } @@ -145,14 +142,12 @@ class DiaryDateActivityService { throw new Error('Activity not found'); } const currentOrderId = activity.orderId; - const scopeGroupId = activity.groupId || null; if (newOrderId < currentOrderId) { await DiaryDateActivity.increment( { orderId: 1 }, { where: { diaryDateId: activity.diaryDateId, - groupId: scopeGroupId, orderId: { [Op.gte]: newOrderId, [Op.lt]: currentOrderId }, }, } @@ -163,7 +158,6 @@ class DiaryDateActivityService { { where: { diaryDateId: activity.diaryDateId, - groupId: scopeGroupId, orderId: { [Op.lte]: newOrderId, [Op.gt]: currentOrderId }, }, } @@ -308,10 +302,7 @@ class DiaryDateActivityService { devLog(predefinedActivity); const maxOrderId = await DiaryDateActivity.max('orderId', { - where: { - diaryDateId, - groupId: Number(groupId) - } + where: { diaryDateId } }); const nextOrderId = Number.isFinite(maxOrderId) ? (maxOrderId + 1) : 1; diff --git a/frontend/src/views/DiaryView.vue b/frontend/src/views/DiaryView.vue index 909fe116..c4cf988f 100644 --- a/frontend/src/views/DiaryView.vue +++ b/frontend/src/views/DiaryView.vue @@ -442,6 +442,18 @@
+ +
@@ -460,6 +472,18 @@
+ +
@@ -2762,16 +2786,68 @@ export default { this.showInfo(this.$t('messages.error'), this.$t('diary.errorOccurred'), '', 'error'); } }, + getOrderedPlanItems() { + return (Array.isArray(this.trainingPlan) ? this.trainingPlan : []) + .filter(item => item && !item.isTimeblock) + .slice() + .sort((a, b) => { + const orderA = Number.isFinite(Number(a?.orderId)) ? Number(a.orderId) : Number.MAX_SAFE_INTEGER; + const orderB = Number.isFinite(Number(b?.orderId)) ? Number(b.orderId) : Number.MAX_SAFE_INTEGER; + if (orderA !== orderB) return orderA - orderB; + return Number(a?.id || 0) - Number(b?.id || 0); + }); + }, + canMovePlanItem(item, direction) { + const orderedItems = this.getOrderedPlanItems(); + const index = orderedItems.findIndex(entry => Number(entry?.id) === Number(item?.id)); + if (index < 0) return false; + if (direction === 'up') return index > 0; + if (direction === 'down') return index < orderedItems.length - 1; + return false; + }, + async movePlanItem(item, direction) { + if (!this.canMovePlanItem(item, direction)) { + return; + } + const orderedItems = this.getOrderedPlanItems(); + const index = orderedItems.findIndex(entry => Number(entry?.id) === Number(item?.id)); + const targetIndex = direction === 'up' ? index - 1 : index + 1; + const targetItem = orderedItems[targetIndex]; + if (!targetItem) return; + + const currentOrder = Number.isFinite(Number(item.orderId)) ? Number(item.orderId) : index + 1; + const targetOrder = Number.isFinite(Number(targetItem.orderId)) ? Number(targetItem.orderId) : targetIndex + 1; + + try { + await apiClient.put(`/diary-date-activities/${this.currentClub}/${item.id}`, { + orderId: targetOrder + }); + await apiClient.put(`/diary-date-activities/${this.currentClub}/${targetItem.id}`, { + orderId: currentOrder + }); + await this.loadTrainingPlan(); + } catch (error) { + this.showInfo(this.$t('messages.error'), this.$t('diary.errorOccurred'), '', 'error'); + } + }, async onDragEnd(evt) { const oldIndex = Number.isInteger(evt.oldDraggableIndex) ? evt.oldDraggableIndex : evt.oldIndex; const newIndex = Number.isInteger(evt.newDraggableIndex) ? evt.newDraggableIndex : evt.newIndex; - const movedItem = this.trainingPlan[oldIndex]; + const visibleItems = this.filteredTrainingPlan.slice(); + const movedId = evt?.item?.dataset?.planId; + const movedItem = movedId + ? this.trainingPlan.find(item => Number(item.id) === Number(movedId)) + : visibleItems[oldIndex]; if (!movedItem) { return; } + const targetItem = visibleItems[newIndex]; + const targetOrder = targetItem && Number(targetItem.id) !== Number(movedItem.id) + ? Number(targetItem.orderId) + : newIndex + 1; try { await apiClient.put(`/diary-date-activities/${this.currentClub}/${movedItem.id}/order`, { - orderId: newIndex + 1 + orderId: targetOrder }); await this.loadTrainingPlan(); } catch (error) {