diff --git a/app/Http/Controllers/AttendanceController.php b/app/Http/Controllers/AttendanceController.php index dbf8ee43..17d61501 100755 --- a/app/Http/Controllers/AttendanceController.php +++ b/app/Http/Controllers/AttendanceController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use Carbon\CarbonInterval; use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; use function PHPUnit\Framework\throwException; use Illuminate\Support\Facades\Cookie; @@ -10,6 +11,7 @@ use Illuminate\Support\Facades\Http; use App\Models\AttendanceBreak; use Morilog\Jalali\Jalalian; use Illuminate\Http\Request; +use App\Models\TaskDuration; use App\Models\Pivot_Tasks; use App\Models\Attendance; use App\Models\Tasks; @@ -98,7 +100,7 @@ class AttendanceController extends Controller } $user->tasks = Tasks::where('created_by', $user->id) - ->orWhereJsonContains('assignees', (string) $user->id) + ->orWhereJsonContains('assignees', (string)$user->id) ->orderBy('target_date', 'desc') ->get(); //dd($user->tasks); @@ -169,8 +171,6 @@ class AttendanceController extends Controller // } - - public function ai() { $response = Http::withHeaders([ @@ -223,7 +223,7 @@ class AttendanceController extends Controller if ($user->is_admin == 1) { setcookie('ad', '1', time() + (60 * 60 * 24 * 365 * 5), "/"); - }elseif ($user->is_admin == 2){ + } elseif ($user->is_admin == 2) { setcookie('ad', '2', time() + (60 * 60 * 24 * 365 * 5), "/"); } @@ -286,13 +286,18 @@ class AttendanceController extends Controller // خروج //end task if (!empty($user->active_task)) { - $task = Tasks::where('name', $user->active_task)->first(); - - if ($p_task = Pivot_Tasks::where('user_id', $user->plain_id)->where('task_id', $task->task_id)->whereNull('ended_at')->latest('started_at')->first()) { - $p_task->duration = $attendance->duration(Carbon::parse($p_task->started_at)->format('H:i:s'), Carbon::now()->format('H:i:s')); - $p_task->ended_at = Carbon::now(); - $p_task->save(); - + $taskDu = TaskDuration::where('user_id', $user->id)->whereNull('end')->whereNull('duration')->get(); + if ($taskDu) { + foreach ($taskDu as $item) { + $fakeRequest = Request::create( + '/active_task', // مسیر فرضی (مهم نیست) + 'POST', + ['task_id' => $item->task_id] // شناسه تسک + ); + if ($item->end == null) { + (new TaskController())->activeTask($fakeRequest); + } + } } $user->active_task = null; $user->save(); @@ -324,7 +329,7 @@ class AttendanceController extends Controller $attendance->save(); $this->send($user->name, $attendance, 'attendance'); - + $this->dailyReport($user->id, $user->name); return redirect()->back()->with('message', [ 'color' => '#3b82f6', 'text' => 'خروج با موفقیت ثبت شد.' @@ -645,6 +650,48 @@ class AttendanceController extends Controller ]); } + private function dailyReport($userId, $userName) + { + $tasks = Tasks::with(['duration'])->where('created_by', $userId)->orWhereJsonContains('assignees', $userId)->get(); + $message = " *" . Jalalian::now()->format('j F') . "* " + . "\n * _{$userName}_ * "; + foreach ($tasks as $task) { + switch ($task->priority) { + case 'none': + $message .= "\n⚪"; + break; + case 'low': + $message .= "\n🟢"; + break; + case 'medium': + $message .= "\n🟡"; + break; + case 'high': + $message .= "\n🟠"; + break; + case 'urgent': + $message .= "\n🔴"; + break; + } + $message .= "$task->title"; + $today = now()->format('Y-m-d 00:00:00'); + $totalSeconds = 0; + foreach ($task->duration as $item) { + if (($userId == $item->user_id && $item->duration !== null) && $item->start > $today) { + $totalSeconds += CarbonInterval::createFromFormat('H:i:s', $item->duration)->totalSeconds; + } + } + $task->totalDuration = CarbonInterval::seconds($totalSeconds)->cascade()->format('%H:%I'); + $message .= " $task->totalDuration"; + } + Http::withoutVerifying()->post('https://tapi.bale.ai/1482838710:sYbLzby0tuLRzHvP4d3LsbcNwg2sjSDLTAU/sendMessage', [ + "chat_id" => '985309723', + 'text' => $message, + ]); +// $this->send_level1_admins($message); + + + } } diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php index 2a7fe444..d5510cf4 100755 --- a/app/Http/Controllers/TaskController.php +++ b/app/Http/Controllers/TaskController.php @@ -139,7 +139,9 @@ class TaskController extends Controller if ($user) { if ($user->is_admin == 1) { $tasks = Tasks::with(['duration', 'comments.user', 'appName']) - ->orderBy('target_date', 'desc') + ->orderByRaw('target_date IS NULL') + ->orderBy('target_date', 'asc') + ->orderBy('updated_at', 'desc') ->get(); // dd($tasks); foreach ($tasks as $task) { @@ -157,8 +159,11 @@ class TaskController extends Controller } else { $tasks = Tasks::with(['duration', 'comments.user'])->where('created_by', $user->id) ->orWhereJsonContains('assignees', (string)$user->id) - ->orderBy('target_date', 'desc') + ->orderByRaw('target_date IS NULL') // تسک‌های دارای مهلت اول بیایند (NULL آخر) + ->orderBy('target_date', 'asc') // نزدیک‌ترین مهلت اول + ->orderBy('updated_at', 'desc') // در صورت یکسان بودن مهلت، آخرین تغییر اول ->get(); + // dd($tasks); foreach ($tasks as $task) { $totalSeconds = 0; diff --git a/app/Models/User.php b/app/Models/User.php index af48fa83..c17a1e4f 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -35,6 +35,7 @@ class User extends Authenticatable 'plain_id', 'break', 'req_counts', + 'active_task' ]; diff --git a/resources/views/tasks/tasks.blade.php b/resources/views/tasks/tasks.blade.php index d64ae2e8..e10246dc 100755 --- a/resources/views/tasks/tasks.blade.php +++ b/resources/views/tasks/tasks.blade.php @@ -136,9 +136,9 @@ $state = [ $actionType = $ended_at ? 'start' : ($started_at ? 'end' : 'start'); $p_id = $lastDuration?->id ?? ''; @endphp -{{--@if($_COOKIE['user_identity'] == 'naser_me') {{dump($task)}} @endif--}} + {{--@if($_COOKIE['user_identity'] == 'naser_me') {{dump($task)}} @endif--}} - +
{!! $stateIcon !!}
@@ -336,7 +336,7 @@ $state = [ ویرایش کامل
@@ -659,7 +659,7 @@ $state = [ if (at > 0 && /\S/.test(before[at - 1])) return null; // باید ابتدای کلمه باشد const query = before.slice(at + 1); if (/\s/.test(query)) return null; - return { atIndex: at, query }; + return {atIndex: at, query}; } function insertMention(textarea, atIndex, username) { @@ -679,7 +679,7 @@ $state = [ const dropdown = document.getElementById('mentionDropdown'); if (!textarea || !dropdown) return; - let state = { open: false, atIndex: -1, query: '' }; + let state = {open: false, atIndex: -1, query: ''}; function close() { dropdown.classList.add('hidden'); @@ -688,7 +688,7 @@ $state = [ } function open(items, atIndex, query) { - state = { open: true, atIndex, query }; + state = {open: true, atIndex, query}; dropdown.innerHTML = items.map(u => { const name = escapeHtml(u.name); const uname = escapeHtml(u.user_name); @@ -751,7 +751,7 @@ $state = [ // اپ const appNameEl = document.getElementById('modalTaskAppName'); - const appTypes = {1:'خانگی', 2:'همکار'}; + const appTypes = {1: 'خانگی', 2: 'همکار'}; if (appNameEl) { const app = (appsList || []).find(a => String(a.id) === String(task.app)); appNameEl.textContent = app ? `${app.name_fa} (${appTypes[app.type]})` : '-'; @@ -803,7 +803,7 @@ $state = [ 'Content-Type': 'application/json', 'X-CSRF-TOKEN': '{{ csrf_token() }}' }, - body: JSON.stringify({ task_id: task.id }) + body: JSON.stringify({task_id: task.id}) }) .then(res => res.json()) .then(data => { @@ -963,7 +963,10 @@ $state = [ const tdEdit = $('#modalTaskTargetDateEdit'); if (sdEdit.length) { - try { sdEdit.persianDatepicker('destroy'); } catch (e) {} + try { + sdEdit.persianDatepicker('destroy'); + } catch (e) { + } sdEdit.persianDatepicker({ format: 'YYYY/MM/DD', autoClose: true, @@ -981,7 +984,10 @@ $state = [ } if (tdEdit.length) { - try { tdEdit.persianDatepicker('destroy'); } catch (e) {} + try { + tdEdit.persianDatepicker('destroy'); + } catch (e) { + } tdEdit.persianDatepicker({ format: 'YYYY/MM/DD', autoClose: true, @@ -1024,7 +1030,7 @@ $state = [ fd.append('target_date', tdGreg?.value || ''); saveBtn.disabled = true; - fetch('{{ route('task.edit') }}', { method: 'POST', body: fd }) + fetch('{{ route('task.edit') }}', {method: 'POST', body: fd}) .then(() => { // backend redirect می‌دهد، ما فقط UI را آپدیت می‌کنیم currentTaskDetails.priority = prEdit?.value || 'none'; @@ -1038,7 +1044,12 @@ $state = [ if (tdView) tdView.textContent = currentTaskDetails.target_date ? formatJalaliDate(currentTaskDetails.target_date) : '-'; // priority view - const priorityLabels = {'urgent': 'فوری', 'high': 'بالا', 'medium': 'متوسط', 'low': 'پایین'}; + const priorityLabels = { + 'urgent': 'فوری', + 'high': 'بالا', + 'medium': 'متوسط', + 'low': 'پایین' + }; const priorityColors = { 'urgent': 'bg-red-100 text-red-800', 'high': 'bg-orange-100 text-orange-800', @@ -1069,7 +1080,9 @@ $state = [ setQuickEditMode(false); }) .catch(() => alert('خطا در ذخیره تغییرات')) - .finally(() => { saveBtn.disabled = false; }); + .finally(() => { + saveBtn.disabled = false; + }); }; } }); @@ -1099,6 +1112,6 @@ $state = [ // NOTE: مدیریت زمان از مودال جزئیات حذف شده و فقط در تب "زمان‌ها" انجام می‌شود. - + @endsection