@extends('layouts.superadmin')
@section('title','Socratic Sentinel — Explorer')
@section('content')
@php
$auditTotal = (is_object($audit) && method_exists($audit,'total')) ? (int)$audit->total() : (is_countable($audit) ? count($audit) : 0);
$trackingCount = (is_countable($tracking) ? count($tracking) : 0);
$failedCount = (is_countable($failed) ? count($failed) : 0);
$jobsCount = (is_countable($jobs) ? count($jobs) : 0);
$membersDeep = $membersDeep ?? [
'total'=>0,'active7'=>0,'active30'=>0,'dormant14'=>0,
'top_visitors_14'=>collect(),'last_seen'=>collect(),'absence_top30'=>collect(),
'eval'=>[
'overall_avg_current'=>0,'overall_avg_prev'=>0,'overall_change_pct'=>0,
'top_improvers'=>collect(),'top_decliners'=>collect(),'anomalies'=>collect(),
],
];
$promission = $promission ?? [
'open'=>0,'completed'=>0,'late'=>0,'completion_rate'=>0,
'stuck'=>collect(),'forecast_bad'=>collect(),'top_assignees'=>collect(),
];
$promissionAlgo = $promissionAlgo ?? [
'from' => $from ?? now()->subDays(14)->toDateString(),
'to' => $to ?? now()->toDateString(),
'compare_mode' => 'prev_month',
'compare_from' => null,
'compare_to' => null,
'compare_enabled' => false,
'goalsTeam' => ['total_hours'=>300,'guest_count'=>100,'live_hours'=>80,'sahra_hours'=>20],
'goalsMember' => ['mix_hours'=>50,'sahra_hours'=>5],
'team' => ['members'=>0,'live_hours'=>0,'sahra_hours'=>0,'guest_hours'=>0,'guest_count'=>0,'total_hours'=>0],
'teamCmp' => null,
'rows' => collect(),
'ai' => ['summary'=>'','tips'=>[]],
];
$algoTeam = $promissionAlgo['team'] ?? [];
$algoGoalsTeam = $promissionAlgo['goalsTeam'] ?? [];
$algoGoalsMember = $promissionAlgo['goalsMember'] ?? [];
$algoRows = collect($promissionAlgo['rows'] ?? collect());
$algoAi = $promissionAlgo['ai'] ?? ['summary'=>'','tips'=>[]];
$pct = function($num, $den){
$den = (float)($den ?? 0);
if($den <= 0) return 0;
return round(((float)$num / $den) * 100, 1);
};
$fmtH = function($h){
return number_format((float)$h, 2);
};
$hitBadge = function($hit){
if(is_null($hit)) return ['cls'=>'bg-white/5 border-white/10 text-white/70','txt'=>'—'];
return $hit
? ['cls'=>'bg-emerald-500/10 border-emerald-400/20 text-emerald-200','txt'=>'محقق ✅']
: ['cls'=>'bg-rose-500/10 border-rose-400/20 text-rose-200','txt'=>'غير محقق ✖'];
};
$compareEnabled = (bool)($promissionAlgo['compare_enabled'] ?? false);
$cmp = $promissionAlgo['teamCmp'] ?? null;
$tone = function($v){
if(is_null($v)) return 'slate';
return ((float)$v >= 0) ? 'emerald' : 'rose';
};
@endphp
{{-- Header --}}
Explorer — Audit + Tracking + Jobs + Members + ProMission
لوحة استكشاف عميقة: سجلات الإدارة + تتبع + طوابير + تعمّق بالأعضاء + أهداف + خوارزمية ProMission.
Audit: {{ number_format($auditTotal) }}
Tracking: {{ number_format($trackingCount) }}
Jobs: {{ number_format($jobsCount) }}
Failed: {{ number_format($failedCount) }}
✅ ملاحظة: يتم عرض الأعضاء المؤهلين فقط (نشط + غير خارج) حسب فلترة الكنترول.
{{-- Tabs --}}
{{-- ✅ NEW TAB: ProMission Algorithm --}}
{{-- ========================= AUDIT ========================= --}}
أحدث عمليات الإدارة (مع Pagination)
| ID |
Action |
Module |
Route |
IP |
At |
@forelse($audit as $row)
| {{ $row->id ?? '—' }} |
{{ $row->action ?? '—' }}
{{ $row->url ?? $row->route_name ?? '—' }}
|
{{ $row->module ?? '—' }} |
{{ $row->route_name ?? '—' }} |
{{ $row->ip_address ?? '—' }}
|
{{ $row->created_at ?? '—' }} |
@empty
| لا يوجد نتائج. |
@endforelse
@if(is_object($audit) && method_exists($audit,'links'))
{{ $audit->links() }}
@endif
{{-- ========================= TRACKING ========================= --}}
@forelse($tracking as $t)
{{ $t->user_id ?? '—' }}
{{ $t->page_url ?? '—' }}
{{ $t->device_type ?? 'device' }}
{{ $t->browser ?? 'browser' }}
IP: {{ $t->ip_address ?? '—' }}
@if(isset($t->load_time) && $t->load_time !== null)
load: {{ number_format((float)$t->load_time, 2) }}s
@endif
{{ $t->visited_at ?? '—' }}
@empty
لا يوجد تتبع ضمن الفترة.
@endforelse
{{-- ========================= JOBS ========================= --}}
| ID |
Queue |
Attempts |
Available At |
Created At |
@forelse($jobs as $j)
| {{ $j->id ?? '—' }} |
{{ $j->queue ?? '—' }} |
{{ $j->attempts ?? '—' }} |
{{ $j->available_at ?? '—' }} |
{{ $j->created_at ?? '—' }} |
@empty
| لا يوجد Jobs. |
@endforelse
{{-- ========================= FAILED ========================= --}}
| ID |
Connection |
Queue |
Failed At |
@forelse($failed as $f)
| {{ $f->id ?? '—' }} |
{{ $f->connection ?? '—' }} |
{{ $f->queue ?? '—' }} |
{{ $f->failed_at ?? '—' }} |
@empty
| لا يوجد Failed Jobs. |
@endforelse
{{-- ========================= MEMBERS DEEP ========================= --}}
{{-- KPIs --}}
نظرة عميقة على الأعضاء (نشاط + خمول + غياب + تقييمات WoW)
{{-- View Toggle for Members Lists --}}
طريقة العرض:
(للجداول/الكروت داخل قسم الأعضاء)
{{-- Top Visitors 14 --}}
{{-- Cards --}}
@forelse(($membersDeep['top_visitors_14'] ?? collect()) as $r)
عضو
ID: {{ $r->user_id ?? '—' }}
visits: {{ number_format((int)($r->visits ?? 0)) }}
days: {{ number_format((int)($r->days ?? 0)) }}
@empty
لا يوجد بيانات.
@endforelse
{{-- Table --}}
| User |
ID |
Visits |
Days |
@forelse(($membersDeep['top_visitors_14'] ?? collect()) as $r)
| {{ $r->name ?? ('#'.($r->user_id ?? '—')) }} |
{{ $r->user_id ?? '—' }} |
@empty
| لا يوجد بيانات. |
@endforelse
{{-- Last Seen --}}
{{-- Cards --}}
@forelse(($membersDeep['last_seen'] ?? collect()) as $r)
عضو
ID: {{ $r->user_id ?? '—' }}
last: {{ $r->last_seen ?? '—' }}
visits14: {{ number_format((int)($r->visits_14 ?? 0)) }}
@empty
لا يوجد بيانات.
@endforelse
{{-- Table --}}
| User |
ID |
Last Seen |
Visits (14) |
@forelse(($membersDeep['last_seen'] ?? collect()) as $r)
| {{ $r->name ?? ('#'.($r->user_id ?? '—')) }} |
{{ $r->user_id ?? '—' }} |
{{ $r->last_seen ?? '—' }} |
@empty
| لا يوجد بيانات. |
@endforelse
{{-- Absences Top 30 --}}
{{-- Cards --}}
@forelse(($membersDeep['absence_top30'] ?? collect()) as $r)
عضو
ID: {{ $r->user_id ?? '—' }}
غيابات: {{ number_format((int)($r->c ?? 0)) }}
@empty
لا يوجد بيانات.
@endforelse
{{-- Table --}}
| User |
ID |
Absences |
@forelse(($membersDeep['absence_top30'] ?? collect()) as $r)
| {{ $r->name ?? ('#'.($r->user_id ?? '—')) }} |
{{ $r->user_id ?? '—' }} |
@empty
| لا يوجد بيانات. |
@endforelse
{{-- Evaluations WoW --}}
@php $ev = $membersDeep['eval'] ?? []; @endphp
متوسط عام + أفضل تحسّن/تراجع + شذوذ
@php
$chg = (float)($ev['overall_change_pct'] ?? 0);
$chgTone = $chg >= 0 ? 'emerald' : 'rose';
@endphp
{{-- Improvers --}}
@forelse(($ev['top_improvers'] ?? collect()) as $r)
cur: {{ $r->cur_avg ?? '—' }} | prev: {{ $r->prev_avg ?? '—' }}
+{{ $r->change_pct ?? '—' }}%
@empty
لا يوجد بيانات.
@endforelse
{{-- Decliners --}}
@forelse(($ev['top_decliners'] ?? collect()) as $r)
cur: {{ $r->cur_avg ?? '—' }} | prev: {{ $r->prev_avg ?? '—' }}
{{ $r->change_pct ?? '—' }}%
@empty
لا يوجد بيانات.
@endforelse
{{-- Anomalies --}}
@forelse(($ev['anomalies'] ?? collect()) as $r)
cur: {{ $r->cur_avg ?? '—' }} | prev: {{ $r->prev_avg ?? '—' }}
{{ $r->change_pct ?? '—' }}%
@empty
لا يوجد بيانات.
@endforelse
{{-- ========================= PROMISSION (TABLE-BASED GOALS) ========================= --}}
ملخص + أهداف عالقة + توقع التأخر + أعلى مُكلّفين (إن وجد)
{{-- Stuck --}}
لم تُحدّث منذ 7 أيام + progress < 80%
@forelse(($promission['stuck'] ?? collect()) as $g)
آخر تحديث: {{ $g->updated_at ?? '—' }}
{{ number_format((float)($g->progress_percent ?? 0), 1) }}%
@empty
لا يوجد أهداف عالقة.
@endforelse
{{-- Forecast Bad --}}
time% مقابل progress% (gap)
@forelse(($promission['forecast_bad'] ?? collect()) as $g)
@php
$gap = isset($g->risk_gap) ? (float)$g->risk_gap : ((float)($g->time_percent ?? 0) - (float)($g->progress_percent ?? 0));
@endphp
progress: {{ number_format((float)($g->progress_percent ?? 0), 1) }}%
— time: {{ number_format((float)($g->time_percent ?? 0), 1) }}%
{{ $g->start_date ?? '—' }} → {{ $g->end_date ?? '—' }}
gap: {{ number_format($gap, 1) }}%
@empty
لا يوجد توقعات خطر حالياً.
@endforelse
{{-- Top Assignees (optional) --}}
يظهر فقط إذا جدول goal_assignments موجود
{{-- Cards --}}
@forelse(($promission['top_assignees'] ?? collect()) as $r)
عضو
ID: {{ $r->user_id ?? '—' }}
tasks: {{ number_format((int)($r->c ?? 0)) }}
done: {{ number_format((float)($r->done_pct ?? 0), 1) }}%
@empty
لا يوجد بيانات (أو الجدول غير موجود).
@endforelse
{{-- Table --}}
| User |
ID |
Tasks |
Done% |
@forelse(($promission['top_assignees'] ?? collect()) as $r)
| {{ $r->name ?? ('#'.($r->user_id ?? '—')) }} |
{{ $r->user_id ?? '—' }} |
@empty
| لا يوجد بيانات. |
@endforelse
{{-- ========================= PROMISSION ALGORITHM (NEW) ========================= --}}
{{-- Summary + Goals Progress --}}
ساعات (لايف + سهرات + قست) + مقارنة + تحليل ذكي — للفترة {{ $promissionAlgo['from'] ?? $from }} → {{ $promissionAlgo['to'] ?? $to }}
Members: {{ number_format((int)($algoTeam['members'] ?? 0)) }}
@if($compareEnabled)
مقارنة: {{ $promissionAlgo['compare_from'] }} → {{ $promissionAlgo['compare_to'] }}
@else
بدون مقارنة
@endif
{{-- Team KPIs --}}
إجمالي الساعات
هدف: {{ $fmtH($algoGoalsTeam['total_hours'] ?? 0) }}س
{{ $pct($algoTeam['total_hours'] ?? 0, $algoGoalsTeam['total_hours'] ?? 0) }}%
لايفات (بدون سهرات)
هدف: {{ $fmtH($algoGoalsTeam['live_hours'] ?? 0) }}س
{{ $pct($algoTeam['live_hours'] ?? 0, $algoGoalsTeam['live_hours'] ?? 0) }}%
سهرات
هدف: {{ $fmtH($algoGoalsTeam['sahra_hours'] ?? 0) }}س
{{ $pct($algoTeam['sahra_hours'] ?? 0, $algoGoalsTeam['sahra_hours'] ?? 0) }}%
ساعات القست
(مرجع: score_records/guest)
عدد القستات
هدف: {{ number_format((int)($algoGoalsTeam['guest_count'] ?? 0)) }}
{{ $pct($algoTeam['guest_count'] ?? 0, $algoGoalsTeam['guest_count'] ?? 0) }}%
{{-- Compare deltas --}}
@if($compareEnabled && $cmp)
@php
$dt = $cmp['delta_total'] ?? null;
$pt = $cmp['pct_total'] ?? null;
$toneT = $tone($dt);
@endphp
نفس فريق الأعضاء — حسب compare_mode
Δ إجمالي: {{ is_null($dt) ? '—' : (($dt>=0?'+':'').$fmtH($dt)) }} س
@if(!is_null($pt)) ({{ $pt }}%) @endif
السابق: {{ $fmtH($cmp['total_hours'] ?? 0) }}س
@php
$dLive = $cmp['delta_live'] ?? null; $tLive = $tone($dLive);
$dSah = $cmp['delta_sahra'] ?? null; $tSah = $tone($dSah);
$dGc = $cmp['delta_guest_count'] ?? null; $tGc = $tone($dGc);
@endphp
Δ ساعات قست
@php $dGh = $cmp['delta_guest_hours'] ?? null; $tGh = $tone($dGh); @endphp
ملاحظة: delta_guest_hours غير محسوب بالكنترول الحالي (اختياري)
@endif
{{-- AI Tips --}}
{{ $algoAi['summary'] ?? '' }}
@forelse(($algoAi['tips'] ?? []) as $tip)
{{ $tip }}
@empty
لا يوجد تحليل حالياً.
@endforelse
{{-- Members Rows --}}
Mix = (لايف بدون سهرات + قست) | Total = Mix + سهرات
هدف العضو: Mix {{ $fmtH($algoGoalsMember['mix_hours'] ?? 0) }}س + سهرات {{ $fmtH($algoGoalsMember['sahra_hours'] ?? 0) }}س
{{-- Cards --}}
@forelse($algoRows as $r)
@php
$hitMix = $hitBadge($r['hit_member_mix'] ?? null);
$hitSah = $hitBadge($r['hit_member_sahra'] ?? null);
$delta = $r['delta_total'] ?? null;
$toneD = $tone($delta);
@endphp
ID: {{ $r['id'] ?? '—' }}
@if(!empty($r['username']))
{{ $r['username'] }}
@endif
قست
({{ (int)($r['guest_count'] ?? 0) }} قست)
Mix: س
Total: س
هدف Mix: {{ $hitMix['txt'] }}
هدف سهرات: {{ $hitSah['txt'] }}
@if($compareEnabled)
Δ Total: {{ is_null($delta) ? '—' : (($delta>=0?'+':'').$fmtH($delta)) }}س
@if(!is_null($r['pct_total'] ?? null)) ({{ $r['pct_total'] }}%) @endif
@endif
@empty
لا يوجد بيانات للفترة.
@endforelse
{{-- Table --}}
| العضو |
لايف |
قست (ساعات) |
قست (عدد) |
سهرات |
Mix |
Total |
هدف Mix |
هدف سهرات |
@if($compareEnabled)
Δ Total |
@endif
@forelse($algoRows as $r)
@php
$hitMix = $hitBadge($r['hit_member_mix'] ?? null);
$hitSah = $hitBadge($r['hit_member_sahra'] ?? null);
$delta = $r['delta_total'] ?? null;
$toneD = $tone($delta);
@endphp
|
{{ $r['name'] ?? ('#'.($r['id'] ?? '—')) }}
ID: {{ $r['id'] ?? '—' }} @if(!empty($r['username'])) — {{ $r['username'] }} @endif
|
{{ number_format((int)($r['guest_count'] ?? 0)) }} |
{{ $hitMix['txt'] }}
|
{{ $hitSah['txt'] }}
|
@if($compareEnabled)
{{ is_null($delta) ? '—' : (($delta>=0?'+':'').$fmtH($delta)) }}
@if(!is_null($r['pct_total'] ?? null)) ({{ $r['pct_total'] }}%) @endif
|
@endif
@empty
| لا يوجد بيانات. |
@endforelse
@endsection