mirror of
https://bitbucket.org/studiotem/jandl-taskmanager-app.git
synced 2026-10-21 14:29:34 +00:00
feat(z-task-modal): enhance timeblock conversion logic and improve draft handling for employee-specific timeblocks
This commit is contained in:
1 parent
81aaa293dd
commit
7a5f354912
4 files changed
+91
-91
No files matched your search
@@ -652,7 +652,7 @@ export default {
|
|||||||
this._update(subtask);
|
this._update(subtask);
|
||||||
},
|
},
|
||||||
|
|
||||||
async toggleTimeblockIsFinished(originalTimeblock, index) {
|
async toggleTimeblockIsFinished(originalTimeblock, _index) {
|
||||||
// Only works for published subtasks with saved timeblocks
|
// Only works for published subtasks with saved timeblocks
|
||||||
if (!originalTimeblock.id) {
|
if (!originalTimeblock.id) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="timeblock">
|
<div
|
||||||
|
class="timeblock"
|
||||||
|
:class="{ 'timeblock--finished': modelValue.is_finished }"
|
||||||
|
>
|
||||||
<a-employee-timeblock-header
|
<a-employee-timeblock-header
|
||||||
:model-value="modelValue"
|
:model-value="modelValue"
|
||||||
:min-date="minDate"
|
:min-date="minDate"
|
||||||
@@ -25,8 +28,12 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Timeline Visualization -->
|
<!-- Timeline Visualization -->
|
||||||
<a-employee-timeblock-timeline
|
<div
|
||||||
v-if="modelValue.date && employee"
|
v-if="modelValue.date && employee"
|
||||||
|
:class="{ 'timeline-wrapper--finished': modelValue.is_finished }"
|
||||||
|
class="timeline-wrapper"
|
||||||
|
>
|
||||||
|
<a-employee-timeblock-timeline
|
||||||
ref="timelineRef"
|
ref="timelineRef"
|
||||||
:is-loading="isLoading"
|
:is-loading="isLoading"
|
||||||
:employee="employee"
|
:employee="employee"
|
||||||
@@ -42,6 +49,7 @@
|
|||||||
@timeblock-updated="handleTimeblockUpdated"
|
@timeblock-updated="handleTimeblockUpdated"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -487,4 +495,9 @@ watch(
|
|||||||
border-radius: 8px
|
border-radius: 8px
|
||||||
margin-bottom: 8px
|
margin-bottom: 8px
|
||||||
overflow: hidden
|
overflow: hidden
|
||||||
|
|
||||||
|
.timeblock--finished
|
||||||
|
opacity: 0.4
|
||||||
|
pointer-events: none
|
||||||
|
cursor: not-allowed
|
||||||
</style>
|
</style>
|
||||||
@@ -11,6 +11,7 @@ export interface TimeblockData {
|
|||||||
starts_at_time: string | null;
|
starts_at_time: string | null;
|
||||||
ends_at_time: string | null;
|
ends_at_time: string | null;
|
||||||
employee_id?: number | null;
|
employee_id?: number | null;
|
||||||
|
is_finished?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmployeeFullData {
|
export interface EmployeeFullData {
|
||||||
|
|||||||
@@ -480,35 +480,32 @@ export default {
|
|||||||
data._deadline_time = splittedDeadline[1];
|
data._deadline_time = splittedDeadline[1];
|
||||||
|
|
||||||
// Convert BE format timeblocks to internal format
|
// Convert BE format timeblocks to internal format
|
||||||
const convertedTimeblocks = [];
|
if (data.is_draft && Array.isArray(data.employees)) {
|
||||||
if (data.timeblocks && data.timeblocks.length > 0) {
|
// Handle draft subtasks with employees array
|
||||||
data.timeblocks.forEach((timeblock) => {
|
const allDraftTimeblocks = [];
|
||||||
// If already in internal format, keep as is
|
|
||||||
if (timeblock.date) {
|
|
||||||
convertedTimeblocks.push({
|
|
||||||
...timeblock,
|
|
||||||
employee_id: data.employee_id, // Add employee_id
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert from BE format to internal format
|
data.employees = data.employees.map((emp) => {
|
||||||
if (timeblock.start && timeblock.end) {
|
const convertedTimeblocks = (emp.timeblocks || [])
|
||||||
const startMoment = moment(timeblock.start, 'YYYY-MM-DD HH:mm:ss');
|
.map((tb) => this._convertTimeblockToInternal(tb, emp.id))
|
||||||
const endMoment = moment(timeblock.end, 'YYYY-MM-DD HH:mm:ss');
|
.filter(Boolean);
|
||||||
convertedTimeblocks.push({
|
|
||||||
id: timeblock.id || null,
|
// Add to flat array for edit mode
|
||||||
date: startMoment.toDate(),
|
allDraftTimeblocks.push(...convertedTimeblocks);
|
||||||
starts_at_time: startMoment.format('HH:mm'),
|
|
||||||
ends_at_time: endMoment.format('HH:mm'),
|
return {
|
||||||
is_finished: timeblock.is_finished || 0,
|
...emp,
|
||||||
employee_id: data.employee_id, // Add employee_id
|
timeblocks: convertedTimeblocks,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update flat timeblocks array for edit mode
|
||||||
|
this.timeblocks = allDraftTimeblocks;
|
||||||
|
} else {
|
||||||
|
// Handle published subtasks with root-level timeblocks
|
||||||
|
this.timeblocks = (data.timeblocks || [])
|
||||||
|
.map((tb) => this._convertTimeblockToInternal(tb, data.employee_id))
|
||||||
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
// Store in component's timeblocks array
|
|
||||||
this.timeblocks = convertedTimeblocks;
|
|
||||||
|
|
||||||
this.subtask = this._enrichTask(data);
|
this.subtask = this._enrichTask(data);
|
||||||
|
|
||||||
@@ -522,6 +519,38 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
/**
|
||||||
|
* Convert a timeblock from backend format to internal format
|
||||||
|
* @param {Object} timeblock - Timeblock in BE format (start/end) or internal format (date/times)
|
||||||
|
* @param {Number} employeeId - Employee ID to associate with the timeblock
|
||||||
|
* @returns {Object} Timeblock in internal format
|
||||||
|
*/
|
||||||
|
_convertTimeblockToInternal(timeblock, employeeId) {
|
||||||
|
// If already in internal format, return as is
|
||||||
|
if (timeblock.date) {
|
||||||
|
return {
|
||||||
|
...timeblock,
|
||||||
|
employee_id: employeeId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert from BE format to internal format
|
||||||
|
if (timeblock.start && timeblock.end) {
|
||||||
|
const startMoment = moment(timeblock.start, 'YYYY-MM-DD HH:mm:ss');
|
||||||
|
const endMoment = moment(timeblock.end, 'YYYY-MM-DD HH:mm:ss');
|
||||||
|
return {
|
||||||
|
id: timeblock.id || null,
|
||||||
|
date: startMoment.toDate(),
|
||||||
|
starts_at_time: startMoment.format('HH:mm'),
|
||||||
|
ends_at_time: endMoment.format('HH:mm'),
|
||||||
|
is_finished: timeblock.is_finished || 0,
|
||||||
|
employee_id: employeeId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
customFilterWithEmployeeFilter(item, input, itemObject) {
|
customFilterWithEmployeeFilter(item, input, itemObject) {
|
||||||
const shouldShowItem = this.customFilter(item, input);
|
const shouldShowItem = this.customFilter(item, input);
|
||||||
|
|
||||||
@@ -749,84 +778,41 @@ export default {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Convert BE format timeblocks to internal format
|
// Convert BE format timeblocks to internal format
|
||||||
const convertedTimeblocks = [];
|
|
||||||
if (data.timeblocks && data.timeblocks.length > 0) {
|
|
||||||
data.timeblocks.forEach((timeblock) => {
|
|
||||||
// If already in internal format, keep as is
|
|
||||||
if (timeblock.date) {
|
|
||||||
convertedTimeblocks.push({
|
|
||||||
...timeblock,
|
|
||||||
employee_id: data.employee_id, // Add employee_id for edit mode
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert from BE format to internal format
|
|
||||||
if (timeblock.start && timeblock.end) {
|
|
||||||
const startMoment = moment(
|
|
||||||
timeblock.start,
|
|
||||||
'YYYY-MM-DD HH:mm:ss',
|
|
||||||
);
|
|
||||||
const endMoment = moment(timeblock.end, 'YYYY-MM-DD HH:mm:ss');
|
|
||||||
convertedTimeblocks.push({
|
|
||||||
id: timeblock.id || null,
|
|
||||||
date: startMoment.toDate(),
|
|
||||||
starts_at_time: startMoment.format('HH:mm'),
|
|
||||||
ends_at_time: endMoment.format('HH:mm'),
|
|
||||||
is_finished: timeblock.is_finished || 0,
|
|
||||||
employee_id: data.employee_id, // Add employee_id for edit mode
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Store timeblocks in the component's timeblocks array
|
|
||||||
this.timeblocks = convertedTimeblocks;
|
|
||||||
|
|
||||||
// If draft with employees data, parse timeblocks for each employee
|
|
||||||
if (
|
if (
|
||||||
data.is_draft &&
|
data.is_draft &&
|
||||||
data.employees &&
|
data.employees &&
|
||||||
Array.isArray(data.employees)
|
Array.isArray(data.employees)
|
||||||
) {
|
) {
|
||||||
|
// Handle draft subtasks with employees array
|
||||||
const draftTimeblocks = [];
|
const draftTimeblocks = [];
|
||||||
|
|
||||||
data.employees.forEach((employee) => {
|
data.employees = data.employees.map((employee) => {
|
||||||
if (employee.timeblocks && Array.isArray(employee.timeblocks)) {
|
const convertedTimeblocks = (employee.timeblocks || [])
|
||||||
employee.timeblocks.forEach((timeblock) => {
|
.map((tb) => this._convertTimeblockToInternal(tb, employee.id))
|
||||||
// Convert BE format to internal format
|
.filter(Boolean);
|
||||||
if (timeblock.start && timeblock.end) {
|
|
||||||
const startMoment = moment(
|
draftTimeblocks.push(...convertedTimeblocks);
|
||||||
timeblock.start,
|
|
||||||
'YYYY-MM-DD HH:mm:ss',
|
return {
|
||||||
);
|
...employee,
|
||||||
const endMoment = moment(
|
timeblocks: convertedTimeblocks,
|
||||||
timeblock.end,
|
};
|
||||||
'YYYY-MM-DD HH:mm:ss',
|
|
||||||
);
|
|
||||||
draftTimeblocks.push({
|
|
||||||
id: timeblock.id || null,
|
|
||||||
date: startMoment.toDate(),
|
|
||||||
starts_at_time: startMoment.format('HH:mm'),
|
|
||||||
ends_at_time: endMoment.format('HH:mm'),
|
|
||||||
is_finished: timeblock.is_finished || 0,
|
|
||||||
employee_id: employee.id, // Associate with employee
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Use draft timeblocks if they exist
|
|
||||||
if (draftTimeblocks.length > 0) {
|
|
||||||
this.timeblocks = draftTimeblocks;
|
this.timeblocks = draftTimeblocks;
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure employees array has proper structure for editing
|
// Ensure employees array has proper structure for editing
|
||||||
// Check if last employee is not empty, then add empty slot
|
|
||||||
const lastEmployee = data.employees[data.employees.length - 1];
|
const lastEmployee = data.employees[data.employees.length - 1];
|
||||||
if (lastEmployee && (lastEmployee.id || lastEmployee.duration)) {
|
if (lastEmployee && (lastEmployee.id || lastEmployee.duration)) {
|
||||||
data.employees.push({});
|
data.employees.push({});
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Handle published subtasks with root-level timeblocks
|
||||||
|
this.timeblocks = (data.timeblocks || [])
|
||||||
|
.map((tb) =>
|
||||||
|
this._convertTimeblockToInternal(tb, data.employee_id),
|
||||||
|
)
|
||||||
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure at least one timeblock exists for edit mode (non-draft single employee)
|
// Ensure at least one timeblock exists for edit mode (non-draft single employee)
|
||||||
|
|||||||
Reference in new issue
Block a user