diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index a03f3b73..1132f5d9 100755 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -22,6 +22,128 @@ use App\Models\Pivot_Tasks; class AdminController extends Controller { + private function loadPendingRequests($users): array + { + $records = []; + + try { + Redis::connection()->ping(); + } catch (\Throwable) { + foreach ($users as $user) { + $records[] = [ + 'user_name' => $user->user_name, + 'name' => $user->name, + 'attendances' => [], + ]; + } + + return $records; + } + + foreach ($users as $user) { + $rec = [ + 'user_name' => $user->user_name, + 'name' => $user->name, + 'attendances' => [], + ]; + + foreach (Redis::keys("att-tempreq:{$user->user_name}:*") as $key) { + if (str_contains($key, ':creates:')) { + continue; + } + + $raw = Redis::get($key); + if (!$raw) { + continue; + } + + $get = json_decode($raw); + if ($get && ($get->function ?? null) !== 'rejected') { + $rec['attendances'][] = $get; + } + } + + $createRequests = Redis::lrange("att-tempreq:creates:{$user->user_name}", 0, -1); + foreach ($createRequests as $reqJson) { + $get = json_decode($reqJson); + if ($get && ($get->function ?? null) !== 'rejected') { + $rec['attendances'][] = $get; + } + } + + $records[] = $rec; + } + + return $records; + } + + private function enrichUsersForDashboard($users): void + { + $userNames = $users->pluck('user_name'); + $now = Carbon::now(); + $monthStart = $now->copy()->startOfMonth(); + $monthEnd = $now->copy()->endOfMonth(); + $today = $now->format('Y-m-d'); + + $monthAttendances = Attendance::query() + ->whereIn('user_identity', $userNames) + ->whereBetween('entered_at', [$monthStart, $monthEnd]) + ->whereNotNull('duration') + ->select(['user_identity', 'duration']) + ->get() + ->groupBy('user_identity'); + + $openAttendances = Attendance::query() + ->whereIn('user_identity', $userNames) + ->whereNull('exited_at') + ->select(['id', 'user_identity', 'entered_at']) + ->get() + ->groupBy('user_identity'); + + $activeBreakAttendanceIds = AttendanceBreak::query() + ->whereIn('attendance_id', $openAttendances->flatten()->pluck('id')) + ->whereNull('break_end') + ->pluck('attendance_id') + ->flip(); + + foreach ($users as $user) { + $totalSeconds = 0; + foreach ($monthAttendances->get($user->user_name, []) as $attendance) { + if (!$attendance->duration) { + continue; + } + $parts = explode(':', $attendance->duration); + if (count($parts) !== 3) { + continue; + } + [$h, $m, $s] = array_map('intval', $parts); + $totalSeconds += ($h * 3600) + ($m * 60) + $s; + } + + $hours = intdiv($totalSeconds, 3600); + $minutes = intdiv($totalSeconds % 3600, 60); + $user->totaltime = sprintf('%02d:%02d', $hours, $minutes); + $user->working = 0; + + $openForUser = $openAttendances->get($user->user_name, collect()); + if ($openForUser->isEmpty()) { + continue; + } + + $latestOpen = $openForUser->sortByDesc('entered_at')->first(); + if ($latestOpen && Carbon::parse($latestOpen->entered_at)->format('Y-m-d') === $today) { + $user->working = 1; + } + + foreach ($openForUser as $openAttendance) { + if ($activeBreakAttendanceIds->has($openAttendance->id)) { + $user->working = 2; + break; + } + } + } + } + public function dashboard() { @@ -29,60 +151,44 @@ class AdminController extends Controller $uname = $_COOKIE['token-0']; setcookie("user_identity", $_COOKIE['token-0'], time() + (60 * 60 * 24 * 365), '/'); Cookie::queue(Cookie::forget('token-0')); - } else - $uname = $_COOKIE['user_identity']; + } else { + $uname = $_COOKIE['user_identity'] ?? null; + } + + if (!$uname) { + return redirect('/')->with('message', [ + 'color' => '#ff8800ff', + 'text' => 'ابتدا باید وارد شوید!' + ]); + } + $u = User::select('name', 'is_admin') ->where('user_name', $uname) ->first(); + + if (!$u) { + return redirect('/')->with('message', [ + 'color' => '#ff8800ff', + 'text' => 'کاربر یافت نشد!' + ]); + } + if ($u->is_admin == 1) { $provider = 'admin'; } elseif ($u->is_admin == 2) { $provider = 'supervisor'; } + if ($u->is_admin == '1' || $u->is_admin == '2') { setcookie('ad', '1', time() + (60 * 60 * 24 * 365 * 5), "/"); - $users = User::wherenotnull('user_name') - ->with('attendances') + $users = User::whereNotNull('user_name') + ->select(['id', 'name', 'user_name', 'req_counts', 'active_task']) ->get(); - $records = []; - foreach ($users as $user) { - $rec = [ - "user_name" => $user->user_name, - "name" => $user->name, - "attendances" => [] - ]; - foreach ($user->attendances as $attendance) { - $key = "att-tempreq:{$user->user_name}:{$attendance->id}"; - $get = json_decode(Redis::get("{$key}")); - $date = $attendance->entered_at ? Carbon::parse($attendance->entered_at)->format('Y-m-d') : null; - if ($get) - if ($get->function != 'rejected') - $rec['attendances'][] = $get; - } -// $key = "att-tempreq:{$user->user_name}:new"; - $create_requests_key = "att-tempreq:creates:{$user->user_name}"; - $create_requests = Redis::connection()->lrange($create_requests_key, 0, -1); // خواندن تمام آیتم های لیست + $this->enrichUsersForDashboard($users); + $users = $users->sortByDesc('working'); + $records = $this->loadPendingRequests($users); - foreach ($create_requests as $req_json) { - $get = json_decode($req_json); - if ($get && $get->function != 'rejected') { - $rec['attendances'][] = $get; - } - } -// $get = json_decode(Redis::get("{$key}")); -// if ($get) { -//// dd($get); -// -// if ($get->function != 'rejected') -// -// $rec['attendances'][] = $get; -// } - $records[] = $rec; - } - -// dd($users); -// dd(json_decode($json,true)); return view("admin..admin")->with(['message', [ 'color' => '#ff8800ff', "text" => 'شما به پنل ادمین وارد شدید✔️' diff --git a/app/Http/Controllers/AttendanceController.php b/app/Http/Controllers/AttendanceController.php index e8e694ea..1c8da0b5 100755 --- a/app/Http/Controllers/AttendanceController.php +++ b/app/Http/Controllers/AttendanceController.php @@ -26,14 +26,14 @@ class AttendanceController extends Controller public function index() { if (isset($_COOKIE['user_identity'])) { + $username = $_COOKIE['user_identity']; + $attendanceSince = Carbon::now()->subMonths(12)->startOfMonth()->format('Y-m-d 00:00:00'); - - $Attendance = isset($_COOKIE['user_identity']) - ? ($_COOKIE['user_identity'] == 1370 - ? Attendance::all() - : Attendance::where('user_identity', $_COOKIE['user_identity'])->get()) - : collect(); - + $Attendance = $username == 1370 + ? Attendance::where('entered_at', '>=', $attendanceSince)->get() + : Attendance::where('user_identity', $username) + ->where('entered_at', '>=', $attendanceSince) + ->get(); $jalalian_object = Jalalian::now(); @@ -48,23 +48,27 @@ class AttendanceController extends Controller ->orderByDesc('id') ->first() ?? ai::where('key', 'angizeh')->orderByDesc('id')->first(); - $ids = array_merge($ids, [$s->id]); - Cookie::queue('seen_angizeh_ids', json_encode($ids), 14400); + if ($s) { + $ids = array_merge($ids, [$s->id]); + Cookie::queue('seen_angizeh_ids', json_encode($ids), 14400); + } //total time $now = Jalalian::fromCarbon(Carbon::now()); $tsec = 0; -//dd(->user_profile); if (isset($_COOKIE['token01'])) { $a = json_decode($_COOKIE['token01']); - $user = User::where('user_name', $a->user_profile)->with('attendances')->first(); + $user = User::where('user_name', $a->user_profile) + ->with(['attendances' => fn($q) => $q->where('entered_at', '>=', $attendanceSince)]) + ->first(); } else { - $user = isset($_COOKIE['user_identity']) ? User::where('user_name', $_COOKIE['user_identity'])->with('attendances')->first() : null; + $user = User::where('user_name', $username) + ->with(['attendances' => fn($q) => $q->where('entered_at', '>=', $attendanceSince)]) + ->first(); } -//dd($user); - if (!empty($user->attendances)) { + if ($user && !empty($user->attendances)) { foreach ($user->attendances as $att) { $date = $att->entered_at != null ? Jalalian::fromCarbon(Carbon::parse($att->entered_at)) : null; $att->date = $date != null ? $date->format('Y/m/d') : null; @@ -83,33 +87,41 @@ class AttendanceController extends Controller $formaction = (isset($_COOKIE['ad']) && $_COOKIE['ad'] == 1) ? 'admin/' : 'attendance/'; - $now = Carbon::now()->format('Y-m-d 00:00:00'); $existed = $Attendance->whereNull('exited_at')->where('entered_at', '>=', now()->format('Y-m-d 00:00:00'))->where('entered_at', '<=', now()->format('Y-m-d 23:59:59'))->first(); - $user = User::where('user_name', $_COOKIE['user_identity'])->first(); $until_now = null; - if ($user->break == 1) { - $att = Attendance::whereNull('exited_at')->latest('entered_at')->first(); - $break = AttendanceBreak::where('attendance_id', $att->id) - ->whereNull('break_end') - ->latest('break_start') + $duration = null; + if ($user && $user->break == 1) { + $att = Attendance::where('user_identity', $user->user_name) + ->whereNull('exited_at') + ->latest('entered_at') ->first(); - if ($break) + $break = $att + ? AttendanceBreak::where('attendance_id', $att->id) + ->whereNull('break_end') + ->latest('break_start') + ->first() + : null; + if ($break) { $until_now = (int)Carbon::parse($break->break_start)->diffInSeconds(now(), false); -// $until_now = Carbon::now()->diffInSeconds(Carbon::parse($break->break_start)); - + $duration = $att->duration($break->break_start, now()->format('Y-m-d H:i:s')); + } } - $user->tasks = Tasks::where('created_by', $user->id) - ->orWhereJsonContains('assignees', (string)$user->id) - ->orderBy('target_date', 'desc') - ->get(); -//dd($user->tasks); -// dd($until_now); + + if ($user) { + $user->tasks = Tasks::where('created_by', $user->id) + ->orWhereJsonContains('assignees', (string)$user->id) + ->orderBy('target_date', 'desc') + ->limit(50) + ->get(); + } + return view('attendance.index', compact('user'))->with([ 's' => $s, 'existed' => $existed, 'formaction' => $formaction, 'breakDu' => $until_now ?? null, + 'duration' => $duration, ]); } else { foreach (request()->cookies as $name => $value) { diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php index 7e4e6167..af249f27 100755 --- a/app/Http/Controllers/TaskController.php +++ b/app/Http/Controllers/TaskController.php @@ -101,6 +101,236 @@ class TaskController extends Controller return implode("\n", $lines); } + + private function sumDurationSeconds($durations, ?int $userId = null): int + { + $totalSeconds = 0; + foreach ($durations as $item) { + if ($userId !== null && (int)$item->user_id !== $userId) { + continue; + } + if ($item->duration === null) { + continue; + } + try { + $totalSeconds += CarbonInterval::createFromFormat('H:i:s', $item->duration)->totalSeconds; + } catch (\Throwable) { + continue; + } + } + + return $totalSeconds; + } + + private function resolveAssigneeNames(Tasks $task, array $usersById = []): array + { + $assignees = is_string($task->assignees) ? json_decode($task->assignees, true) : $task->assignees; + $assignees = is_array($assignees) ? array_map('strval', $assignees) : []; + + if (empty($assignees)) { + return []; + } + + if (!empty($usersById)) { + $names = []; + foreach ($assignees as $id) { + if (!empty($usersById[$id])) { + $names[] = $usersById[$id]; + } + } + + return $names; + } + + return User::whereIn('id', $assignees)->pluck('name')->all(); + } + + private function buildTasksPayload($tasks, array $usersById = []): array + { + $payload = []; + foreach ($tasks as $task) { + $payload[$task->id] = [ + 'id' => $task->id, + 'title' => $task->title, + 'description' => $task->description, + 'start_date' => $task->start_date, + 'target_date' => $task->target_date, + 'priority' => $task->priority, + 'state' => $task->state, + 'app' => $task->app, + 'active' => (bool)$task->active, + 'creator_name' => $task->creator_name, + 'created_at' => $task->created_at, + 'assignee_names' => $task->assignee_names ?? $this->resolveAssigneeNames($task, $usersById), + 'total_duration' => $task->total_duration ?? '00:00:00', + 'comments' => [], + 'duration' => [], + ]; + } + + return $payload; + } + + private function userCanAccessTask(Tasks $task, User $user): bool + { + if ($user->is_admin == 1) { + return true; + } + + $assignees = is_string($task->assignees) ? json_decode($task->assignees, true) : $task->assignees; + $assignees = is_array($assignees) ? array_map('strval', $assignees) : []; + + return (int)$task->created_by === (int)$user->id + || in_array((string)$user->id, $assignees, true); + } + + private function buildTaskDetailPayload(Tasks $task, bool $isAdmin, User $user): array + { + $activeQuery = TaskDuration::query() + ->where('task_id', $task->id) + ->whereNull('end'); + + if (!$isAdmin) { + $activeQuery->where('user_id', $user->id); + } + + return [ + 'id' => $task->id, + 'title' => $task->title, + 'description' => $task->description, + 'start_date' => $task->start_date, + 'target_date' => $task->target_date, + 'priority' => $task->priority, + 'state' => $task->state, + 'app' => $task->app, + 'active' => $activeQuery->exists(), + 'creator_name' => $task->creator?->name ?? 'نامشخص', + 'created_at' => $task->created_at, + 'assignee_names' => $this->resolveAssigneeNames($task), + 'duration' => $task->duration->map(fn ($d) => [ + 'id' => $d->id, + 'task_id' => $d->task_id, + 'user_id' => $d->user_id, + 'start' => $d->start, + 'end' => $d->end, + 'duration' => $d->duration, + ])->values()->all(), + 'comments' => $task->comments->map(fn ($c) => [ + 'id' => $c->id, + 'body' => $c->body, + 'created_at' => $c->created_at, + 'user' => $c->user ? ['name' => $c->user->name] : null, + ])->values()->all(), + ]; + } + + private function loadTasksPageData(User $user): array + { + $isAdmin = $user->is_admin == 1; + + $query = Tasks::query() + ->select([ + 'id', + 'title', + 'description', + 'start_date', + 'target_date', + 'priority', + 'state', + 'app', + 'created_by', + 'assignees', + 'created_at', + 'updated_at', + ]) + ->with([ + 'appName:id,name_fa,type', + 'creator:id,name', + ]) + ->orderByRaw('target_date IS NULL') + ->orderBy('target_date', 'asc') + ->orderBy('updated_at', 'desc'); + + if (!$isAdmin) { + $query->where(function ($q) use ($user) { + $q->where('created_by', $user->id) + ->orWhereJsonContains('assignees', (string)$user->id); + }); + } + + $tasks = $query->get(); + $taskIds = $tasks->pluck('id'); + + $assigneeIds = []; + foreach ($tasks as $task) { + $ids = is_string($task->assignees) ? json_decode($task->assignees, true) : $task->assignees; + if (is_array($ids)) { + $assigneeIds = array_merge($assigneeIds, array_map('strval', $ids)); + } + } + $usersById = !empty($assigneeIds) + ? User::whereIn('id', array_unique($assigneeIds)) + ->get() + ->mapWithKeys(fn ($user) => [(string)$user->id => $user->name]) + ->all() + : []; + + if ($taskIds->isEmpty()) { + return [ + 'tasks' => $tasks, + 'tasksPayload' => [], + 'assigneeFilterOptions' => [], + ]; + } + + $activeQuery = TaskDuration::query() + ->select(['task_id']) + ->whereIn('task_id', $taskIds) + ->whereNull('end'); + + if (!$isAdmin) { + $activeQuery->where('user_id', $user->id); + } + + $activeTaskIds = $activeQuery->pluck('task_id')->flip(); + + $durationQuery = TaskDuration::query() + ->select(['task_id', 'user_id', 'duration']) + ->whereIn('task_id', $taskIds) + ->whereNotNull('duration'); + + if (!$isAdmin) { + $durationQuery->where('user_id', $user->id); + } + + $durationsByTaskId = $durationQuery->get()->groupBy('task_id'); + + foreach ($tasks as $task) { + $task->active = $activeTaskIds->has($task->id); + $task->creator_name = $task->creator?->name ?? 'نامشخص'; + $task->assignee_names = $this->resolveAssigneeNames($task, $usersById); + $ids = is_string($task->assignees) ? json_decode($task->assignees, true) : $task->assignees; + $task->assignee_ids = is_array($ids) ? array_map('strval', $ids) : []; + $totalSeconds = $this->sumDurationSeconds( + $durationsByTaskId->get($task->id, collect()), + $isAdmin ? null : $user->id + ); + $task->total_duration = CarbonInterval::seconds($totalSeconds)->cascade()->format('%H:%I:%S'); + } + + $assigneeFilterOptions = collect($usersById) + ->map(fn ($name, $id) => ['id' => (string)$id, 'name' => $name]) + ->sortBy('name', SORT_NATURAL) + ->values() + ->all(); + + return [ + 'tasks' => $tasks, + 'tasksPayload' => $this->buildTasksPayload($tasks, $usersById), + 'assigneeFilterOptions' => $assigneeFilterOptions, + ]; + } + // public function tasks() // { // $user = User::where('user_name', $_COOKIE['user_identity'])->first(); @@ -135,61 +365,27 @@ class TaskController extends Controller public function tasks() { + if (!isset($_COOKIE['user_identity'])) { + return redirect('/')->with('message', [ + 'color' => 'red', + 'text' => 'ابتدا باید وارد شوید!' + ]); + } + $user = User::where('user_name', $_COOKIE['user_identity'])->first(); if ($user) { - if ($user->is_admin == 1) { - $tasks = Tasks::with(['duration', 'comments.user', 'appName']) - ->orderByRaw('target_date IS NULL') - ->orderBy('target_date', 'asc') - ->orderBy('updated_at', 'desc') - ->get(); -// dd($tasks); - foreach ($tasks as $task) { - $totalSeconds = 0; - foreach ($task->duration as $item) { - if ($item->duration !== null) { - $totalSeconds += CarbonInterval::createFromFormat('H:i:s', $item->duration)->totalSeconds; - } - } - - $task->totalDuration = CarbonInterval::seconds($totalSeconds)->cascade()->format('%H:%I:%S'); - $active_task = TaskDuration::where('task_id', $task->id)->orderBy('start', 'desc')->first(); - $task->active = !empty($active_task) && $active_task->end == null; - } - } else { - $tasks = Tasks::with(['duration', 'comments.user'])->where('created_by', $user->id) - ->orWhereJsonContains('assignees', (string)$user->id) -// ->orderByRaw('target_date IS NULL') -// ->orderBy('target_date', 'asc') - ->orderBy('updated_at', 'desc') - ->get(); - -// dd($tasks); - foreach ($tasks as $task) { - $totalSeconds = 0; - foreach ($task->duration as $item) { - if ($user->id == $item->user_id && $item->duration !== null) { - $totalSeconds += CarbonInterval::createFromFormat('H:i:s', $item->duration)->totalSeconds; - } - } - - $task->totalDuration = CarbonInterval::seconds($totalSeconds)->cascade()->format('%H:%I:%S'); - $active_task = TaskDuration::where('task_id', $task->id)->where('user_id', $user->id)->orderBy('start', 'desc')->first(); - $task->active = !empty($active_task) && $active_task->end == null; - } - } - - $count = count($tasks); - -// dd((new Tasks())->filterByState($tasks)['backlog'][0], 'count ='.$count); + ['tasks' => $tasks, 'tasksPayload' => $tasksPayload, 'assigneeFilterOptions' => $assigneeFilterOptions] = $this->loadTasksPageData($user); + $count = $tasks->count(); return view('tasks.tasks', [ 'tasks' => (new Tasks())->filterByState($tasks), + 'tasksPayload' => $tasksPayload, + 'assigneeFilterOptions' => $assigneeFilterOptions, 'count' => $count, 'user_id' => $user->id, 'isAdminLevel1' => $user->is_admin == 1, 'mentionUsers' => User::select('id', 'name', 'user_name')->get(), - 'appsList' => App::select('id', 'name_fa')->get(), + 'appsList' => App::select('id', 'name_fa', 'type')->get(), 'priorityLabels' => [ 'urgent' => 'فوری', 'high' => 'بالا', @@ -220,6 +416,37 @@ class TaskController extends Controller } + public function taskDetailsJson($id) + { + if (!isset($_COOKIE['user_identity'])) { + return response()->json(['error' => 'Unauthorized'], 401); + } + + $user = User::where('user_name', $_COOKIE['user_identity'])->first(); + if (!$user) { + return response()->json(['error' => 'User not found'], 404); + } + + $isAdmin = $user->is_admin == 1; + $task = Tasks::query() + ->with([ + 'creator:id,name', + 'comments.user:id,name', + 'duration' => function ($q) use ($isAdmin, $user) { + if (!$isAdmin) { + $q->where('user_id', $user->id); + } + }, + ]) + ->find($id); + + if (!$task || !$this->userCanAccessTask($task, $user)) { + return response()->json(['error' => 'Not found'], 404); + } + + return response()->json($this->buildTaskDetailPayload($task, $isAdmin, $user)); + } + public function editTask(Request $request) { // dd($request->all()); @@ -342,6 +569,10 @@ class TaskController extends Controller public function activeTask(Request $request) { // dd($request); + if (!isset($_COOKIE['user_identity'])) { + return response()->json(['action' => 'unauthorized', 'status' => false], 401); + } + $user = User::where('user_name', $_COOKIE['user_identity'])->first(); $task = Tasks::find($request->task_id); if (!$task) { diff --git a/app/Models/Tasks.php b/app/Models/Tasks.php index 64275fc6..1bf8c9a6 100755 --- a/app/Models/Tasks.php +++ b/app/Models/Tasks.php @@ -62,6 +62,11 @@ class Tasks extends Model return $this->belongsTo(User::class); } + public function creator() + { + return $this->belongsTo(User::class, 'created_by'); + } + public function appName(){ return $this->belongsTo(App::class, 'app' , 'id'); } diff --git a/composer.lock b/composer.lock index 343d4b3b..69293a37 100755 --- a/composer.lock +++ b/composer.lock @@ -2348,25 +2348,27 @@ }, { "name": "nette/schema", - "version": "v1.3.2", + "version": "v1.3.5", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "da801d52f0354f70a638673c4a0f04e16529431d" + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d", - "reference": "da801d52f0354f70a638673c4a0f04e16529431d", + "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002", + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002", "shasum": "" }, "require": { "nette/utils": "^4.0", - "php": "8.1 - 8.4" + "php": "8.1 - 8.5" }, "require-dev": { - "nette/tester": "^2.5.2", - "phpstan/phpstan-nette": "^1.0", + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.6", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1.39@stable", "tracy/tracy": "^2.8" }, "type": "library", @@ -2376,6 +2378,9 @@ } }, "autoload": { + "psr-4": { + "Nette\\": "src" + }, "classmap": [ "src/" ] @@ -2404,35 +2409,37 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.3.2" + "source": "https://github.com/nette/schema/tree/v1.3.5" }, - "time": "2024-10-06T23:10:23+00:00" + "time": "2026-02-23T03:47:12+00:00" }, { "name": "nette/utils", - "version": "v4.0.7", + "version": "v4.1.4", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2" + "reference": "7da6c396d7ebe142bc857c20479d5e70a5e1aac7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2", + "url": "https://api.github.com/repos/nette/utils/zipball/7da6c396d7ebe142bc857c20479d5e70a5e1aac7", + "reference": "7da6c396d7ebe142bc857c20479d5e70a5e1aac7", "shasum": "" }, "require": { - "php": "8.0 - 8.4" + "php": "8.2 - 8.5" }, "conflict": { "nette/finder": "<3", "nette/schema": "<1.2.2" }, "require-dev": { - "jetbrains/phpstorm-attributes": "dev-master", + "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", "nette/tester": "^2.5", - "phpstan/phpstan": "^1.0", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -2446,10 +2453,13 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { + "psr-4": { + "Nette\\": "src" + }, "classmap": [ "src/" ] @@ -2490,9 +2500,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.7" + "source": "https://github.com/nette/utils/tree/v4.1.4" }, - "time": "2025-06-03T04:55:08+00:00" + "time": "2026-05-11T20:49:54+00:00" }, { "name": "nikic/php-parser", @@ -8288,12 +8298,12 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^8.2" }, - "platform-dev": [], - "plugin-api-version": "2.6.0" + "platform-dev": {}, + "plugin-api-version": "2.9.0" } diff --git a/config/auth.php b/config/auth.php index 44939c7c..f51770ae 100755 --- a/config/auth.php +++ b/config/auth.php @@ -40,6 +40,14 @@ return [ 'driver' => 'session', 'provider' => 'users', ], + 'user' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + 'customer' => [ + 'driver' => 'session', + 'provider' => 'users', + ], 'admin' => [ 'driver' => 'jwt', 'provider' => 'admins', diff --git a/package-lock.json b/package-lock.json index e6f4c0e3..6639a401 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "a.montask", + "name": "a_montask", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/resources/views/admin/admin.blade.php b/resources/views/admin/admin.blade.php index a76f140e..2b95655d 100755 --- a/resources/views/admin/admin.blade.php +++ b/resources/views/admin/admin.blade.php @@ -1,63 +1,9 @@ attendances as $att) { - $date = $att->entered_at != null ? Jalalian::fromCarbon(Carbon::parse($att->entered_at)) : null; - $att->date = $date != null ? $date->format('Y/m/d') : null; - if ($att->duration != null && $date != null && $now->getMonth() == $date->getMonth()) { - [$h, $m, $s] = explode(':', $att->duration); - $tsec += $h * 3600 + $m * 60 + $s; - } - } - $hours = floor($tsec / 3600); - $minutes = floor(($tsec % 3600) / 60); - $seconds = $tsec % 60; - - $totalTime = sprintf('%02d:%02d', $hours, $minutes); - $user->totaltime = $totalTime; - -} -//dd($users); -$now = now()->format('Y-m-d'); -foreach ($users as $u) { - - $us = $u->attendances() - ->whereNull('exited_at') - ->latest('entered_at') - ->first(); -// dump($us); - if ($us) { - $us->entered_at = Carbon::parse($us->entered_at)->format('Y-m-d'); - if ($us->entered_at == $now) - $us = true; - else - $us = false; - $u->working = $us ? 1 : 0; - } else - $u->working = 0; - - foreach ($u->attendances as $u_att) { - $break = AttendanceBreak::wherenull('break_end')->where('attendance_id', $u_att->id)->exists(); - if ($break) - $u->working = 2; - } - -} -//dd($users); -$users = $users->sortByDesc('working'); -//$users = json_decode(json: $users); -// $users = collect($users); $usersChunked = $users->chunk(3); -//dd($users); ?> @@ -66,43 +12,35 @@ $usersChunked = $users->chunk(3);
@if(!collect($reqs)->pluck('attendances')->flatten()->isEmpty()) -
-

درخواست ها

- {{-- {{dd($reqs)}}--}} +
+

درخواست ها

@foreach ($reqs as $u) @if(!empty($u['attendances'])) - - {{-- @else--}} - {{--

درخواستی ثبت نشده

--}} - {{-- @break--}} @endif -
- +
+
+
- - - - - - - {{-- @if($userType == 'admin')--}} - - {{-- @endif--}} + + + + + + {{-- {{dd($u['attendances'])}}--}} @forelse($u['attendances'] as $rec) - + {{--{{dd($rec)}}--}}
درخواستتاریخورودخروجتعیین وضعیت
درخواستتاریخورودخروجتعیین وضعیت
{{ match ($rec->function) { 'edit' => "تغییر ساعت", @@ -138,8 +76,7 @@ $usersChunked = $users->chunk(3); - @@ -148,8 +85,7 @@ $usersChunked = $users->chunk(3); - @@ -163,7 +99,8 @@ $usersChunked = $users->chunk(3); @endforelse
-
{{-- پایان hidden-content --}} +
+
@endforeach {{-- @if(collect($reqs)->pluck('attendances')->flatten()->isEmpty())--}} {{--

درخواستی ثبت نشده

--}} @@ -175,38 +112,29 @@ $usersChunked = $users->chunk(3);
@foreach ($usersChunked as $chunk) @foreach ($chunk as $u) -
- @php - @endphp - -

- {{ $u->name ?? $u->user_name }} -

+ @php + $cardClass = 'ui-user-card m-3'; + if ($u->active_task) { + $cardClass .= ' is-active'; + } elseif ($u->working == 1) { + $cardClass .= ' is-working'; + } elseif ($u->working == 2) { + $cardClass .= ' is-break'; + } + @endphp +
+ +

{{ $u->name ?? $u->user_name }}

@if($u->active_task)

وظیفه: {{ $u->active_task }}

@endif -

- کارکرد ماه جاری: - {{ $u->totaltime }} -

- -

- تعداد درخواست ها: - {{ $u->req_counts }} -

- +

کارکرد ماه جاری: {{ $u->totaltime }}

+

تعداد درخواست ها: {{ $u->req_counts }}

@if($userType == 'admin') - @endif @@ -214,10 +142,8 @@ $usersChunked = $users->chunk(3); @endforeach @endforeach - - + +
diff --git a/resources/views/admin/index.blade.php b/resources/views/admin/index.blade.php index cfbc8a4a..b20cc490 100755 --- a/resources/views/admin/index.blade.php +++ b/resources/views/admin/index.blade.php @@ -224,7 +224,7 @@ SVG; @else -
+
Profile Picture