@php
// Since we now use safe tab IDs,
// the positionKey IS the safe tab ID
$tabKey = $positionKey;
$allStandardItems = collect();
if (isset($standardItemsBySet[$tabKey])) {
$allStandardItems = collect(
$standardItemsBySet[$tabKey],
)
->sortBy('order')
->unique(function ($item) {
return strtolower(
trim($item->name ?? ''),
);
})
->values();
}
// Resolve standard items (and rating signature) from standard set id.
// This is used to detect month differences even when evaluation items are still empty.
$standardItemsBySetCache = [];
$buildItemsFromStandardSetId = function (
$standardSetId,
) use (&$standardItemsBySetCache) {
if (!$standardSetId) {
return collect();
}
if (
isset(
$standardItemsBySetCache[
$standardSetId
],
)
) {
return $standardItemsBySetCache[
$standardSetId
];
}
$items = DB::table('mst_pa_standard_item')
->where('standard_set_id', $standardSetId)
->where('isactive', '1')
->orderBy('order')
->get();
if ($items->isEmpty()) {
$standardItemsBySetCache[
$standardSetId
] = collect();
return $standardItemsBySetCache[
$standardSetId
];
}
$itemIds = $items
->pluck('id')
->filter()
->values();
$ratingsByItem = collect();
if ($itemIds->isNotEmpty()) {
$ratingsByItem = DB::table(
'mst_pa_standard_rating',
)
->whereIn('standard_item_id', $itemIds)
->orderBy('score')
->get()
->groupBy('standard_item_id');
}
$resolvedItems = $items
->map(function ($item) use (
$ratingsByItem,
) {
$ratingSignature = collect(
$ratingsByItem->get($item->id) ??
[],
)
->map(function ($rating) {
return trim(
($rating->score ?? '-') .
'|' .
($rating->label ?? '-'),
);
})
->implode('||');
return (object) [
'id' => $item->id,
'name' => $item->name,
'order' => $item->order,
'weight' => $item->weight,
'rating_signature' =>
$ratingSignature ?: '-',
];
})
->values();
$standardItemsBySetCache[
$standardSetId
] = $resolvedItems;
return $standardItemsBySetCache[$standardSetId];
};
// Resolve expected standard set for month when segment/evaluation item does not exist.
$expectedStandardByMonthCache = [];
$buildItemsFromMonth = function ($monthKey) use (
&$expectedStandardByMonthCache,
$master,
$buildItemsFromStandardSetId,
) {
if (
isset(
$expectedStandardByMonthCache[
$monthKey
],
)
) {
return $expectedStandardByMonthCache[
$monthKey
];
}
$monthDate = \Carbon\Carbon::createFromFormat(
'Y-m',
$monthKey,
)->startOfMonth();
$monthAssignment = DB::table(
'trs_employee_assignment',
)
->where(
'employee_nik',
$master->employee_nik,
)
->where(
'effective_from',
'<=',
$monthDate->toDateString(),
)
->where(function ($q) use ($monthDate) {
$q->whereNull('effective_to')->orWhere(
'effective_to',
'>=',
$monthDate->toDateString(),
);
})
->where('isactive', '1')
->orderBy('effective_from', 'desc')
->first();
if (!$monthAssignment) {
$expectedStandardByMonthCache[
$monthKey
] = collect();
return $expectedStandardByMonthCache[
$monthKey
];
}
$calendarMonth = DB::table('mst_calendar_month')
->where('year', $monthDate->year)
->where('month', $monthDate->month)
->first();
if (!$calendarMonth) {
$expectedStandardByMonthCache[
$monthKey
] = collect();
return $expectedStandardByMonthCache[
$monthKey
];
}
$expectedStandardSet = DB::table(
'mst_pa_standard_set',
)
->where(
'calendar_month_id',
$calendarMonth->id,
)
->where(
'pa_position_id',
$monthAssignment->pa_position_id,
)
->first();
if (!$expectedStandardSet) {
$expectedStandardByMonthCache[
$monthKey
] = collect();
return $expectedStandardByMonthCache[
$monthKey
];
}
$expectedStandardByMonthCache[
$monthKey
] = $buildItemsFromStandardSetId(
$expectedStandardSet->id,
);
return $expectedStandardByMonthCache[$monthKey];
};
// Build month metadata and group months by standards+criteria signature.
// If signature differs, the UI will split into separate tabs.
$monthMeta = collect();
foreach ($setData['months'] as $monthKey) {
$segment = $segmentsByMonth[$monthKey] ?? null;
$monthLabel = \Carbon\Carbon::createFromFormat(
'Y-m',
$monthKey,
)->format('M Y');
$monthStandardItems = collect();
if (
$segment &&
isset($evaluationItems[$segment->id]) &&
$evaluationItems[$segment->id]->isNotEmpty()
) {
$monthStandardItems = $evaluationItems[
$segment->id
]
->sortBy('item_order')
->map(function ($item) use (
$allRatings,
) {
return (object) [
'id' => $item->standard_item_id,
'name' => $item->item_name,
'order' => $item->item_order,
'weight' => $item->item_weight,
'rating_signature' => isset(
$allRatings[
$item->standard_item_id
],
)
? $allRatings[
$item->standard_item_id
]
->map(function ($r) {
return trim(
($r->score ??
'-') .
'|' .
($r->label ??
'-'),
);
})
->implode('||')
: '-',
];
})
->unique(function ($item) {
return strtolower(
trim($item->name ?? ''),
);
})
->values();
} else {
// Prefer month-specific expected standard set to avoid merging different months.
if (
$segment &&
!empty($segment->standard_set_id)
) {
$monthStandardItems = $buildItemsFromStandardSetId(
$segment->standard_set_id,
);
}
if ($monthStandardItems->isEmpty()) {
$monthStandardItems = $buildItemsFromMonth(
$monthKey,
);
}
if ($monthStandardItems->isEmpty()) {
$monthStandardItems = $allStandardItems
->map(function ($item) {
return (object) [
'id' => $item->id ?? null,
'name' =>
$item->name ?? '-',
'order' =>
$item->order ?? 0,
'weight' =>
$item->weight ?? 0,
'rating_signature' => '-',
];
})
->values();
}
}
$monthSignature = $monthStandardItems
->map(function ($item) {
return trim(
($item->name ?? '-') .
'|' .
($item->order ?? 0) .
'|' .
($item->rating_signature ??
'-'),
);
})
->implode('###');
$monthMeta->push([
'month_key' => $monthKey,
'month_label' => $monthLabel,
'signature' => $monthSignature,
'standard_items' => $monthStandardItems,
]);
}
$monthGroups = $monthMeta
->groupBy('signature')
->values()
->map(function ($group, $index) use (
$allStandardItems,
$tabKey,
) {
$groupStandardItems = $group
->pluck('standard_items')
->flatten(1)
->sortBy('order')
->unique(function ($item) {
return strtolower(
trim($item->name ?? ''),
);
})
->values();
if ($groupStandardItems->isEmpty()) {
$groupStandardItems = $allStandardItems;
}
return [
'group_id' =>
'std-group-' .
$tabKey .
'-' .
$index,
'months' => $group
->pluck('month_key')
->values(),
'month_labels' => $group
->pluck('month_label')
->values(),
'standard_items' => $groupStandardItems,
];
})
->values();
$hasDifferentStandards = $monthGroups->count() > 1;
$hasAnyStandardItems = $monthGroups->contains(
function ($group) {
return $group[
'standard_items'
]->isNotEmpty();
},
);
@endphp
@if ($hasAnyStandardItems)
@if ($hasDifferentStandards)
Ditemukan perbedaan standar/deskripsi antar
bulan. Tampilan dipisah per tab agar lebih mudah
dibandingkan.
@foreach ($monthGroups as $group)
@php
$groupLabel =
$group[
'month_labels'
]->count() > 1
? $group[
'month_labels'
]->implode(', ')
: $group[
'month_labels'
]->first() ?? '-';
@endphp
-
@endforeach
@endif
@foreach ($monthGroups as $group)
|
Standar PA
|
@foreach ($group['months'] as $monthKey)
@php
$monthLabel = \Carbon\Carbon::createFromFormat(
'Y-m',
$monthKey,
)->format(
'M Y',
);
$segment =
$segmentsByMonth[
$monthKey
] ?? null;
$restMonth =
$restMonths[
$monthKey
] ?? null;
@endphp
@if ($restMonth)
{{ $monthLabel }}
({{ ucfirst($restMonth->reason) }})
|
@elseif($segment)
{{ $monthLabel }}
@if (isset($lateMonths[$monthKey]) && $lateMonths[$monthKey])
TERLAMBAT
@endif
|
@else
{{ $monthLabel }}
(Kosong)
|
@endif
@endforeach
@foreach ($group['months'] as $monthKey)
@php
$segment =
$segmentsByMonth[
$monthKey
] ?? null;
$restMonth =
$restMonths[
$monthKey
] ?? null;
@endphp
@if ($restMonth)
|
- |
- |
- |
- |
@elseif($segment)
Bobot (%)
|
Nilai
|
Alasan |
Score |
@else
- |
- |
- |
- |
@endif
@endforeach
@foreach ($group['standard_items'] as $standardItem)
|
{{ $standardItem->name }}
|
@foreach ($group['months'] as $monthKey)
@php
$segment =
$segmentsByMonth[
$monthKey
] ??
null;
$restMonth =
$restMonths[
$monthKey
] ??
null;
$evaluationItem = null;
// Find evaluation item for this standard item and segment
if (
$segment &&
isset(
$evaluationItems[
$segment
->id
],
)
) {
// First try exact match by standard_item_id
$evaluationItem = $evaluationItems[
$segment
->id
]->firstWhere(
'standard_item_id',
$standardItem->id,
);
// If no exact match, try matching by name and order only (not weight)
// Weight can be different for same standard name in different months
if (
!$evaluationItem
) {
$evaluationItem = $evaluationItems[
$segment
->id
]->first(
function (
$item,
) use (
$standardItem,
) {
return $item->item_name ===
$standardItem->name &&
$item->item_order ==
$standardItem->order;
},
);
}
}
@endphp
@if ($restMonth)
Sedang Cuti
|
@elseif($evaluationItem)
{{-- Bobot --}}
@php
$currentWeight =
$evaluationItem->final_weight ??
($evaluationItem->item_weight ??
$standardItem->weight);
$defaultWeight =
$evaluationItem->item_weight ??
$standardItem->weight;
$isInactive =
$currentWeight ==
0;
@endphp
status ?? null) === 'approved' ? 'disabled' : '' }}>
@if ($isInactive)
Nonaktif
@endif
|
{{-- Rating --}}
@php
$evalItemId =
$evaluationItem->id; // ID trs_pa_evaluation_item (pasti ada)
$stdItemId =
$evaluationItem->standard_item_id;
$finalRatingId =
$evaluationItem->final_rating_id ??
null;
$originalRatingId =
$evaluationItem->original_rating_id ??
null;
// Skor & Label ORIGINAL (handle null)
$originalRatingScore =
$evaluationItem->original_rating_score ??
null; // Bisa null
$originalRatingLabel =
$evaluationItem->original_rating_label ??
'';
// Format data-original-rating seperti yang diharapkan JS lama
$originalRatingAttrValue = !is_null(
$originalRatingScore,
)
? "{$originalRatingScore} - {$originalRatingLabel}"
: ''; // Kosong jika original null
// Skor & Label FINAL (handle null)
$finalRatingScore =
$evaluationItem->final_rating_score ??
null; // Bisa null
$finalRatingLabel =
$evaluationItem->final_rating_label ??
'';
// Tampilan default jika final rating null
$displayScore =
'-';
$displayLabel =
'Belum Dinilai';
$badgeClass =
'bg-secondary';
// Jika final rating TIDAK null, gunakan nilainya
if (
!is_null(
$finalRatingId,
)
) {
// Cek apakah rating valid ada di $allRatings (safety check)
if (
isset(
$allRatings[
$stdItemId
],
) &&
($foundRating = collect(
$allRatings[
$stdItemId
],
)->firstWhere(
'id',
$finalRatingId,
))
) {
$displayScore =
$foundRating->score; // Gunakan skor dari $allRatings
$displayLabel =
$foundRating->label; // Gunakan label dari $allRatings
$badgeClass =
'bg-primary';
} else {
// Fallback jika ID ada tapi rating tidak ketemu
$displayScore =
'?';
$displayLabel =
'Rating Tdk Valid';
$badgeClass =
'bg-danger';
// Log::warning(...) bisa ditambahkan di sini
}
}
// Tentukan apakah perlu menampilkan skor original di badge
$isDifferentFromOriginal =
$finalRatingId !=
$originalRatingId;
// Tampilkan hanya jika item di-revise DAN berbeda DAN original score ada
$showOriginalScoreInBadge =
$evaluationItem->is_revised ==
1 &&
$isDifferentFromOriginal &&
!is_null(
$originalRatingScore,
);
@endphp
{{-- Hidden select: Harus ada opsi null, dan data-original-rating format lama --}}
{{-- Badge: Tampilan visual, onclick only if not inactive --}}
{{ $displayScore }}
{{-- Skor final atau '-' --}}
{{-- Tampilkan skor original jika perlu (pastikan $originalRatingScore tidak null) --}}
@if ($showOriginalScoreInBadge)
({{ $originalRatingScore }})
{{-- Tampilkan skor original --}}
@endif
|
{{-- Kolom Alasan Revisi dan Skor --}}
{{-- ... (kode untuk textarea alasan dan skor tetap sama) ... --}}
{{-- Alasan Revisi --}}
|
|
{{-- Score --}}
{{ rtrim(rtrim(number_format($evaluationItem->weighted_score ?? 0, 2), '0'), '.') }}
|
@elseif($segment)
{{-- Segment ada, item evaluasi tidak ada --}}
- |
No Data |
- |
- |
@else
{{-- Tidak ada segment --}}
Belum
Dinilai |
@endif
@endforeach
@endforeach
|
Total Bobot
|
@foreach ($group['months'] as $monthKey)
@php
$segment =
$segmentsByMonth[
$monthKey
] ?? null;
$restMonth =
$restMonths[
$monthKey
] ?? null;
@endphp
@if ($restMonth)
0%
|
@elseif($segment)
|
|
|
|
@else
-
|
@endif
@endforeach
@endforeach
@else
Tidak ada
standard item untuk posisi ini.
@endif