diff --git a/frontend/src/views/DiaryView.vue b/frontend/src/views/DiaryView.vue index 752289af..530adf9d 100644 --- a/frontend/src/views/DiaryView.vue +++ b/frontend/src/views/DiaryView.vue @@ -412,7 +412,12 @@
| {{ $t('diary.startTime') }} | +Gemeinsam | +{{ group.name }} | +|
|---|---|---|---|
| {{ $t('diary.startTime') }} | {{ $t('diary.activityOrTimeblock') }} | @@ -421,7 +426,54 @@||
| {{ formatDisplayTime(row.startTime) }} | +
+
+
+ -
+
+
+
+ {{ getPlanItemDisplayLabel(item) }}
+
+ {{ getPlanItemStatus(item).label }}
+
+
+
+
+
+
+
+ |
+
+
+
+ -
+
+
+
+ {{ getPlanItemDisplayLabel(item) }}
+
+ {{ getPlanItemStatus(item).label }}
+
+
+
+
+
+
+
+ |
+ |
| {{ calculateNextTime }} | ++ {{ $t('diary.planAddHint') }} + | +||
| ☰ | @@ -1047,6 +1099,71 @@ export default { standalonePlanItemCount() { return (this.trainingPlan || []).filter(item => item && !item.isTimeblock).length; }, + showGroupedPlanTable() { + return this.planGroupFilter === '__all__' && Array.isArray(this.groups) && this.groups.length > 0; + }, + groupedPlanRows() { + if (!this.showGroupedPlanTable) return []; + const rowsByKey = new Map(); + const toMinutes = (timeValue) => { + if (!timeValue || typeof timeValue !== 'string' || !timeValue.includes(':')) { + return Number.MAX_SAFE_INTEGER; + } + const [h, m] = timeValue.split(':').map((part) => parseInt(part, 10)); + if (!Number.isFinite(h) || !Number.isFinite(m)) { + return Number.MAX_SAFE_INTEGER; + } + return (h * 60) + m; + }; + + for (const item of (this.trainingPlan || [])) { + if (!item || item.isTimeblock) continue; + const key = item.startTime || `unknown-${item.id}`; + if (!rowsByKey.has(key)) { + rowsByKey.set(key, { + key, + startTime: item.startTime || '', + sharedItems: [], + groupItems: {} + }); + } + const row = rowsByKey.get(key); + const groupId = Number(item.groupId); + if (Number.isFinite(groupId) && groupId > 0) { + if (!Array.isArray(row.groupItems[groupId])) { + row.groupItems[groupId] = []; + } + row.groupItems[groupId].push(item); + } else { + row.sharedItems.push(item); + } + } + + const sortItems = (items) => items.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); + }); + + const rows = Array.from(rowsByKey.values()).map((row) => { + row.sharedItems = sortItems(row.sharedItems); + for (const group of this.groups || []) { + const groupId = Number(group.id); + if (Array.isArray(row.groupItems[groupId])) { + row.groupItems[groupId] = sortItems(row.groupItems[groupId]); + } + } + return row; + }); + + return rows.sort((a, b) => { + const startA = toMinutes(a?.startTime); + const startB = toMinutes(b?.startTime); + if (startA !== startB) return startA - startB; + return String(a?.key || '').localeCompare(String(b?.key || '')); + }); + }, filteredTrainingPlan() { const allItems = Array.isArray(this.trainingPlan) ? this.trainingPlan : []; const toMinutes = (timeValue) => { @@ -1541,6 +1658,7 @@ export default { initializeSortable() { const el = this.$refs.sortableList; + if (!el) return; Sortable.create(el, { draggable: '.plan-sortable-row', handle: ".drag-handle", @@ -2836,6 +2954,17 @@ export default { const value = String(timeValue); return value.length >= 5 ? value.slice(0, 5) : value; }, + getPlanItemDisplayLabel(item) { + if (!item) return ''; + const predefined = item.predefinedActivity || item.groupPredefinedActivity; + if (predefined?.code && predefined.code.trim() !== '') { + return predefined.code; + } + if (predefined?.name) { + return predefined.name; + } + return item.activity || ''; + }, editGroup(groupId) { this.editingGroupId = groupId; }, @@ -5297,6 +5426,22 @@ img { flex-wrap: wrap; } +.plan-cell-stack { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.plan-cell-item { + display: flex; + flex-direction: column; + gap: 0.35rem; + padding: 0.35rem 0.4rem; + border: 1px solid #e4edf2; + border-radius: 8px; + background: #f9fcfe; +} + .plan-row-action-button { border: 1px solid #cfdbe3; background: #f3f7fa;