Add timeframe selection and improve goal progress calculations in DepartmentGoals.vue
- Introduced timeframe selection tabs for viewing goals by different periods. - Updated `getGoalProgress` and department progress calculations to incorporate selected timeframe. - Enhanced goal progress display to reflect accurate departmental and overall progress based on current timeframe.
This commit is contained in:
@@ -16,6 +16,10 @@ const loading = ref(true);
|
||||
const activeTab = ref('active');
|
||||
const toast = useToast();
|
||||
|
||||
const timeframe = ref('all');
|
||||
|
||||
const currentTimeframe = computed(() => timeframe.value);
|
||||
|
||||
const fetchGoals = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -79,10 +83,18 @@ const getGoalIconColor = (type) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getGoalProgress = (goal) => {
|
||||
const getGoalProgress = (goal, deptId = null) => {
|
||||
const key = currentTimeframe.value;
|
||||
// Use the .value to divided by .target and multiply by 100
|
||||
const value = parseFloat(goal.progress?.all?.count);
|
||||
const target = parseFloat(goal.progress?.all?.target);
|
||||
if (deptId && goal.progress?.departmental_distribution?.[deptId]?.[key]) {
|
||||
const deptValue = parseFloat(goal.progress.departmental_distribution[deptId][key].count);
|
||||
const deptTarget = getDailyGoalDepartmentTarget(goal, deptId, true);
|
||||
if (isNaN(deptValue) || isNaN(deptTarget) || deptTarget === 0) return 0;
|
||||
const deptProgress = (deptValue / deptTarget) * 100;
|
||||
return Math.min(Math.round(deptProgress), 100);
|
||||
}
|
||||
const value = parseFloat(goal.progress?.[key]?.count);
|
||||
const target = parseFloat(goal.progress?.[key]?.target);
|
||||
if (isNaN(value) || isNaN(target) || target === 0) return 0;
|
||||
const progress = (value / target) * 100;
|
||||
return Math.min(Math.round(progress), 100);
|
||||
@@ -162,9 +174,13 @@ const getDailyGoalDepartmentTarget = (goal, deptId, progressUntilNow = false) =>
|
||||
return isNaN(x) ? 0 : x;
|
||||
};
|
||||
const getEvenSplitPerDay = () => {
|
||||
if (daysTotal === 0) return goal.criteria.target; // Avoid division by zero
|
||||
if (daysTotal === 0) return goal.progress?.departmental_distribution?.[deptId]?.[currentTimeframe]?.target || 0;
|
||||
const deptCount = Math.max(1, goal.departments.length || 1);
|
||||
return (normalizeInt(goal.criteria.target) / deptCount) / daysTotal;
|
||||
// If the department has a custom daily target, use that, otherwise use the even split
|
||||
if (hasOverride) {
|
||||
return normalizeInt(overrides[String(deptId)]);
|
||||
}
|
||||
return (normalizeInt(goal.progress?.departmental_distribution?.[deptId]?.[currentTimeframe]?.target) || (normalizeInt(goal.criteria.target) / deptCount)) / daysTotal;
|
||||
};
|
||||
const dailyTarget = hasOverride ? normalizeInt(overrides[String(deptId)]) : getEvenSplitPerDay();
|
||||
|
||||
@@ -255,6 +271,36 @@ const getGoalApplicableDaysInPeriod = (goal, fromDate, toDate) => {
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Timeframe -->
|
||||
<div class="tabs is-toggle is-fullwidth mb-5">
|
||||
<ul>
|
||||
<li :class="{ 'is-active': timeframe === 'all' }" @click="timeframe = 'all'">
|
||||
<a>
|
||||
<span class="icon is-small"><i class="fas fa-list"></i></span>
|
||||
<span>Alle</span>
|
||||
</a>
|
||||
</li>
|
||||
<li :class="{ 'is-active': timeframe === 'today' }" @click="timeframe = 'today'">
|
||||
<a>
|
||||
<span class="icon is-small"><i class="fas fa-calendar-day"></i></span>
|
||||
<span>I dag</span>
|
||||
</a>
|
||||
</li>
|
||||
<li :class="{ 'is-active': timeframe === 'week' }" @click="timeframe = 'week'">
|
||||
<a>
|
||||
<span class="icon is-small"><i class="fas fa-calendar-week"></i></span>
|
||||
<span>Denne uge</span>
|
||||
</a>
|
||||
</li>
|
||||
<li :class="{ 'is-active': timeframe === 'month' }" @click="timeframe = 'month'">
|
||||
<a>
|
||||
<span class="icon is-small"><i class="fas fa-calendar-alt"></i></span>
|
||||
<span>Denne måned</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div v-if="loading" class="section has-text-centered py-6">
|
||||
<span class="icon is-large">
|
||||
@@ -317,12 +363,12 @@ const getGoalApplicableDaysInPeriod = (goal, fromDate, toDate) => {
|
||||
<div class="mb-5">
|
||||
<div class="is-flex is-justify-content-space-between mb-2">
|
||||
<span class="is-size-7 has-text-weight-semibold">Fremskridt</span>
|
||||
<span class="is-size-7 has-text-weight-bold"><small>{{ goal.progress.all?.count || 0 }} / {{ goal.criteria.target }}</small> - <strong>{{ getGoalProgress(goal) }}%</strong></span>
|
||||
<span class="is-size-7 has-text-weight-bold"><small>{{ goal.progress[currentTimeframe]?.count || 0 }} / {{ Math.round(goal.progress[currentTimeframe]?.target || goal.progress[currentTimeframe]?.target || goal.criteria.target) }}</small> - <strong>{{ getGoalProgress(goal) }}%</strong></span>
|
||||
</div>
|
||||
<progress
|
||||
class="progress is-small mb-0"
|
||||
:value="goal.progress.all?.count || 0"
|
||||
:max="goal.criteria.target"
|
||||
:value="goal.progress[currentTimeframe]?.count || 0"
|
||||
:max="goal.progress[currentTimeframe]?.target || goal.criteria.target"
|
||||
:class="getProgressClass(getGoalProgress(goal))"
|
||||
>
|
||||
{{ getGoalProgress(goal) }}%
|
||||
@@ -332,7 +378,7 @@ const getGoalApplicableDaysInPeriod = (goal, fromDate, toDate) => {
|
||||
<div class="columns is-mobile">
|
||||
<div class="column">
|
||||
<p class="heading mb-1">Mål</p>
|
||||
<p class="subtitle is-6 has-text-weight-bold">{{ goal.criteria.type === 'REVENUE' ? SessionUser.functions.currency.toLocal(goal.criteria.target) : goal.criteria.target }}</p>
|
||||
<p class="subtitle is-6 has-text-weight-bold">{{ goal.criteria.type === 'REVENUE' ? SessionUser.functions.currency.toLocal(goal.progress[currentTimeframe]?.target || goal.criteria.target) : goal.progress[currentTimeframe]?.target || goal.criteria.target }}</p>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="heading mb-1">Periode</p>
|
||||
@@ -349,20 +395,20 @@ const getGoalApplicableDaysInPeriod = (goal, fromDate, toDate) => {
|
||||
<b-tooltip position="is-left" type="is-dark">
|
||||
<template v-slot:content>
|
||||
<div>
|
||||
<!-- Until today -->
|
||||
<div class="divider mt-0">Fremskridt til dd.</div>
|
||||
<!-- Progress in selected timeframe for this department -->
|
||||
<div class="divider mt-0">Valgt tidsramme</div>
|
||||
<!-- Departmental progress and then % with 2 decimal places -->
|
||||
<template v-if="goal.departments.length > 1" v-for="tmpDeptId in goal.departments" :key="tmpDeptId">
|
||||
<!-- The target for this department until today -->
|
||||
<div class="is-flex is-justify-content-space-between mb-1">
|
||||
<strong :class="{'has-text-warning': tmpDeptId === deptId, 'has-text-grey': tmpDeptId !== deptId}">{{ getDepartmentName(tmpDeptId) }}</strong>
|
||||
<span :class="{'has-text-warning': tmpDeptId === deptId, 'has-text-grey': tmpDeptId !== deptId}">{{ goal.progress.departmental_distribution[tmpDeptId]?.all?.count || 0 }} / {{ getDailyGoalDepartmentTarget(goal, tmpDeptId, true) }} - <strong :class="{'has-text-warning': tmpDeptId === deptId, 'has-text-grey': tmpDeptId !== deptId}">{{ Math.min(Math.round(((goal.progress.departmental_distribution[tmpDeptId]?.all?.count || 0) / getDailyGoalDepartmentTarget(goal, tmpDeptId, true)) * 100, true), 100) }}%</strong></span>
|
||||
<span :class="{'has-text-warning': tmpDeptId === deptId, 'has-text-grey': tmpDeptId !== deptId}">{{ goal.progress.departmental_distribution[tmpDeptId]?.[currentTimeframe]?.count || 0 }} / {{ getDailyGoalDepartmentTarget(goal, tmpDeptId, true) }} - <strong :class="{'has-text-warning': tmpDeptId === deptId, 'has-text-grey': tmpDeptId !== deptId}">{{ Math.min(Math.round(((goal.progress.departmental_distribution[tmpDeptId]?.[currentTimeframe]?.count || 0) / getDailyGoalDepartmentTarget(goal, tmpDeptId, true)) * 100, true), 100) }}%</strong></span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Total progress until now for all departments -->
|
||||
<div class="is-flex is-justify-content-space-between mb-1">
|
||||
<strong class="has-text-white">I alt</strong>
|
||||
<span>{{ goal.progress.all?.count || 0 }} / {{ getDailyGoalDepartmentTarget(goal, deptId, true) * goal.departments.length }} - <strong class="has-text-white">{{ getGoalProgress(goal) }}%</strong></span>
|
||||
<span>{{ goal.progress[currentTimeframe]?.count || 0 }} / {{ goal.progress[currentTimeframe]?.target || (getDailyGoalDepartmentTarget(goal, deptId, true) * goal.departments.length) }} - <strong class="has-text-white">{{ getGoalProgress(goal) }}%</strong></span>
|
||||
</div>
|
||||
<!-- Total divider -->
|
||||
<div class="divider">I alt</div>
|
||||
@@ -370,7 +416,7 @@ const getGoalApplicableDaysInPeriod = (goal, fromDate, toDate) => {
|
||||
<div class="is-flex is-justify-content-space-between mb-1">
|
||||
<strong class="has-text-white">Mål</strong>
|
||||
<!-- Overall goal progress and then % with 2 decimal places -->
|
||||
<span>{{ goal.progress.all?.count || 0 }} / {{ goal.criteria.target }} - <strong class="has-text-white">{{ getGoalProgress(goal) }}%</strong></span>
|
||||
<span>{{ goal.progress[currentTimeframe]?.count || 0 }} / {{ goal.progress[currentTimeframe]?.target || goal.criteria.target }} - <strong class="has-text-white">{{ getGoalProgress(goal) }}%</strong></span>
|
||||
</div>
|
||||
<!-- Days since -->
|
||||
<div class="is-flex is-justify-content-space-between mb-1">
|
||||
@@ -385,18 +431,18 @@ const getGoalApplicableDaysInPeriod = (goal, fromDate, toDate) => {
|
||||
</template>
|
||||
<template v-slot:default>
|
||||
<span>
|
||||
<strong>{{ Math.min(Math.round(((goal.progress.departmental_distribution[deptId]?.all?.count || 0) / getDailyGoalDepartmentTarget(goal, deptId, true)) * 100, true), 100) }}%</strong>
|
||||
<strong>{{ Math.min(Math.round(((goal.progress.departmental_distribution[deptId]?.[currentTimeframe]?.count || 0) / goal.progress.departmental_distribution[deptId]?.[currentTimeframe]?.target) * 100, true), 100) }}%</strong>
|
||||
</span>
|
||||
</template>
|
||||
</b-tooltip>
|
||||
</div>
|
||||
<progress
|
||||
class="progress is-small mb-0"
|
||||
:value="goal.progress.departmental_distribution[deptId]?.all?.count || 0"
|
||||
:max="getDailyGoalDepartmentTarget(goal, deptId, true)"
|
||||
:class="getProgressClass(getDailyGoalDepartmentTarget(goal, deptId, true) === 0 ? 0 : Math.min(Math.round(((goal.progress.departmental_distribution[deptId]?.all?.count || 0) / getDailyGoalDepartmentTarget(goal, deptId, true)) * 100, true), 100))"
|
||||
:value="goal.progress.departmental_distribution[deptId]?.[currentTimeframe]?.count || 0"
|
||||
:max="goal.progress.departmental_distribution[deptId]?.[currentTimeframe]?.target || getDailyGoalDepartmentTarget(goal, deptId, true)"
|
||||
:class="getProgressClass(getDailyGoalDepartmentTarget(goal, deptId, true) === 0 ? 0 : Math.min(Math.round(((goal.progress.departmental_distribution[deptId]?.[currentTimeframe]?.count || 0) / goal.progress.departmental_distribution[deptId]?.[currentTimeframe]?.target) * 100, true), 100))"
|
||||
>
|
||||
{{ Math.min(Math.round(((goal.progress.departmental_distribution[deptId]?.all?.count || 0) / getDailyGoalDepartmentTarget(goal, deptId)) * 100, true), 100) }}%
|
||||
{{ Math.min(Math.round(((goal.progress.departmental_distribution[deptId]?.[currentTimeframe]?.count || 0) / goal.progress.departmental_distribution[deptId]?.[currentTimeframe]?.target) * 100, true), 100) }}%
|
||||
</progress>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user