342 lines
21 KiB
PHP
342 lines
21 KiB
PHP
<?php
|
|
|
|
use Morilog\Jalali\Jalalian;
|
|
use Carbon\Carbon;
|
|
use App\Models\Pivot_Tasks;
|
|
|
|
|
|
$backlog = <<<SVG
|
|
<svg height="12px" width="12px" viewBox="0 0 16 16" class="flex-shrink-0 flex-shrink-0 size-4" xmlns="http://www.w3.org/2000/svg"><g>
|
|
<g transform="translate(8 8) rotate(-90)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(-66)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(-42)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(-18)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(6)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(30)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(54)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(78)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(102)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(126)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(150)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(174)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(198)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(222)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g><g transform="translate(8 8) rotate(246)"><line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#60646C" stroke-width="1.21" stroke-linecap="round">
|
|
</line></g></g>
|
|
</svg>
|
|
SVG;
|
|
$todo = <<<SVG
|
|
<svg width="12px" height="12px" viewBox="0 0 16 16" class="flex-shrink-0 flex-shrink-0 size-4"><g></g>
|
|
<circle cx="8" cy="8" r="6" fill="none" stroke="#60646C" stroke-width="1.5" stroke-dasharray="37.69911184307752" stroke-dashoffset="0" stroke-linecap="round" transform="rotate(-90 8 8)">
|
|
</circle></svg>
|
|
SVG;
|
|
$error = <<<SVG
|
|
<svg width="12px" height="12px" viewBox="0 0 16 16" class="flex-shrink-0 flex-shrink-0 size-4"><g><g transform="translate(8 8) rotate(102)">
|
|
<line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#eb144c" stroke-width="1.21" stroke-linecap="round"></line></g><g transform="translate(8 8) rotate(126)">
|
|
<line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#eb144c" stroke-width="1.21" stroke-linecap="round"></line></g><g transform="translate(8 8) rotate(150)">
|
|
<line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#eb144c" stroke-width="1.21" stroke-linecap="round"></line></g><g transform="translate(8 8) rotate(174)">
|
|
<line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#eb144c" stroke-width="1.21" stroke-linecap="round"></line></g><g transform="translate(8 8) rotate(198)">
|
|
<line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#eb144c" stroke-width="1.21" stroke-linecap="round"></line></g><g transform="translate(8 8) rotate(222)">
|
|
<line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#eb144c" stroke-width="1.21" stroke-linecap="round"></line></g><g transform="translate(8 8) rotate(246)">
|
|
<line x1="5.75" y1="0" x2="6.5" y2="0" stroke="#eb144c" stroke-width="1.21" stroke-linecap="round"></line></g></g><circle cx="6" cy="6" r="3" stroke-width="1.5" stroke-linecap="round" fill="none" transform="rotate(-90 8 6)" stroke-dasharray="37.69911184307752" stroke-dashoffset="0" stroke="#eb144c">
|
|
</circle><circle cx="8" cy="8" r="6" fill="none" stroke="#eb144c" stroke-width="1.5" stroke-dasharray="37.69911184307752" stroke-dashoffset="18.84955592153876" stroke-linecap="round" transform="rotate(-90 8 8)"></circle></svg>
|
|
SVG;
|
|
$in_progress = <<<SVG
|
|
<svg width="12px" height="12px" viewBox="0 0 16 16" class="flex-shrink-0 flex-shrink-0 size-4"><g></g><circle cx="6" cy="6" r="3" stroke-width="1.5" stroke-linecap="round" fill="none" transform="rotate(-90 8 6)" stroke-dasharray="37.69911184307752" stroke-dashoffset="0" stroke="#F59E0B"></circle><circle cx="8" cy="8" r="6" fill="none" stroke="#F59E0B" stroke-width="1.5" stroke-dasharray="37.69911184307752" stroke-dashoffset="0" stroke-linecap="round" transform="rotate(-90 8 8)"></circle></svg>
|
|
SVG;
|
|
$done = <<<SVG
|
|
<svg height="12px" width="12px" class="flex-shrink-0 flex-shrink-0 size-4" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" percentage="1"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15ZM11.3587 6.18828C11.6007 5.85214 11.5244 5.38343 11.1882 5.14141C10.8521 4.89938 10.3834 4.97568 10.1414 5.31183L7.03706 9.62335L5.25956 7.97751C4.95563 7.69609 4.4811 7.71434 4.19968 8.01828C3.91826 8.32221 3.93651 8.79673 4.24045 9.07815L6.64045 11.3004C6.79816 11.4464 7.01095 11.5178 7.22481 11.4963C7.43868 11.4749 7.63307 11.3627 7.75865 11.1883L11.3587 6.18828Z" fill="#46A758"></path></svg>
|
|
SVG;
|
|
$cancelled = <<<SVG
|
|
<svg height="12px" width="12px" class="flex-shrink-0 flex-shrink-0 size-4" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" percentage="1"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15ZM11.1018 4.89826C11.3947 5.19115 11.3947 5.66603 11.1018 5.95892L9.06068 8.00002L11.1018 10.0411C11.3947 10.334 11.3947 10.8089 11.1018 11.1018C10.8089 11.3947 10.334 11.3947 10.0411 11.1018L8.00002 9.06068L5.95892 11.1018C5.66603 11.3947 5.19115 11.3947 4.89826 11.1018C4.60537 10.8089 4.60537 10.334 4.89826 10.0411L6.93936 8.00002L4.89826 5.95892C4.60537 5.66603 4.60537 5.19115 4.89826 4.89826C5.19115 4.60537 5.66603 4.60537 5.95892 4.89826L8.00002 6.93936L10.0411 4.89826C10.334 4.60537 10.8089 4.60537 11.1018 4.89826Z" fill="#9AA4BC"></path></svg>
|
|
SVG;
|
|
|
|
$state = [
|
|
"c73c2044-ea14-42cb-b08d-cecf3d1fdfb5" => "$in_progress",// in progress
|
|
"a9ce312f-cfca-491e-8e3d-1975aa6ebc10" => "$todo",//to do
|
|
"dea1fb57-a281-4fe7-8f3e-ee5567637e35" => "$error",// error
|
|
"770fbe42-99f6-41db-9b9e-773d9cced1a5" => "$backlog",//backlog
|
|
"b0e464e1-34eb-41ea-b2f7-3ef7483bc9f0" => "$done",//done
|
|
"d61d14a3-72f7-4f44-894b-efe8b2a75be1" => "$cancelled",//canceled
|
|
];
|
|
|
|
$p_tasks = Pivot_Tasks::get();
|
|
|
|
foreach ($work_item as $work) {
|
|
$duration = '00:00:00';
|
|
$totalSeconds = 0;
|
|
|
|
|
|
$items = $sub_work_items->where('parent', $work->task_id);
|
|
if (count($items) >= 1) {
|
|
foreach ($items as $item) {
|
|
|
|
|
|
|
|
|
|
$p_t = $p_tasks->where('task_id', $item->task_id)->first();
|
|
// dump($item->task_id, $p_t?->duration);
|
|
if (!empty($p_t)) {
|
|
|
|
$item->p_id = $p_t->id;
|
|
$item->started_at = $p_t->started_at;
|
|
$item->ended_at = $p_t->ended_at;
|
|
$item->duration = $p_t->duration;
|
|
if ($p_t->duration !== null) {
|
|
// dump($p_t->duration);
|
|
|
|
[$h1, $m1, $s1] = explode(':', $p_t->duration);
|
|
$durationSeconds = $h1 * 3600 + $m1 * 60 + $s1;
|
|
|
|
$totalSeconds += $durationSeconds;
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
$hours = floor($totalSeconds / 3600);
|
|
$minutes = floor(($totalSeconds % 3600) / 60);
|
|
$seconds = $totalSeconds % 60;
|
|
|
|
$duration = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
|
|
}
|
|
$work->total_duration = $duration ?? '00:00:00';
|
|
}
|
|
//dd($work_item,'sub',$sub_work_items);
|
|
?>
|
|
@extends('app')
|
|
@section('content')
|
|
|
|
<div class="container w-full flex justify-center items-center flex-col ">
|
|
{{-- {{dd(count($tasks))}}--}}
|
|
@if(count($tasks) > 0)
|
|
{{-- <div class="bg-white p-4 rounded-lg shadow-md mt-10 w-[350px] text-center">--}}
|
|
{{-- <h1 class="text-xl font-bold">--}}
|
|
{{-- وظیفه ها--}}
|
|
{{-- </h1>--}}
|
|
{{-- </div>--}}
|
|
<div class="mt-10">
|
|
@foreach($work_item as $t)
|
|
{{-- {{dump(Pivot_Tasks::where('task_id',$t->task_id)->whereNotNull('duration')->first())}}--}}
|
|
{{-- {{dump($t->total_duration)}}--}}
|
|
<div class="bg-white p-4 rounded-lg shadow-md mt-[10px] w-[350px] text-center flex flex-col items-center">
|
|
<button type="button"
|
|
onclick="togglerequests('name-{{ $loop->index }}')"
|
|
class="relative flex items-center justify-center w-full text-center py-2">
|
|
|
|
<!-- آیکون سمت چپ -->
|
|
{!! array_key_exists($t->state,$state) ? $state[$t->state] : "" !!}
|
|
|
|
<!-- متن وسط -->
|
|
<span class="mx-auto">{{$t->name}}</span>
|
|
</button>
|
|
{{-- @endforeach--}}
|
|
{{-- @foreach($tasks as $t)--}}
|
|
<div id="name-{{ $loop->index }}" class="hidden border-gray-300 border-t-2 border-dotted">
|
|
<div class=" w-[350px] text-center flex flex-col items-center">
|
|
@if(isset($t->description_html) && strlen(trim(strip_tags($t->description_html))) > 0)
|
|
<p class="mt-2 text-gray-600 ">
|
|
توضیحات: {!! $t->description_html !!}
|
|
</p>
|
|
@endif
|
|
@if(isset($t->start_date))
|
|
<p class="mt-2 ">
|
|
شروع وظیفه: {{$t->start_date ? Jalalian::fromCarbon(Carbon::parse($t->start_date))->format('Y/m/d') : ''}}
|
|
</p>
|
|
@endif
|
|
@if(isset($t->target_date))
|
|
<p class="mt-2 ">
|
|
پایان وظیفه: {{$t->target_date ? Jalalian::fromCarbon(Carbon::parse($t->target_date))->format('Y/m/d') : ''}}
|
|
</p>
|
|
@endif
|
|
|
|
<p class="mt-2 text-gray-600 border-gray-300 {{ isset($t->description_html) && strlen(trim(strip_tags($t->description_html))) > 0 ?
|
|
'border-t-2 border-dotted w-full pt-2' : ''}}">
|
|
ایجاد شده توسط {{$t->created_by}}
|
|
</p>
|
|
<p class="mt-2 text-gray-600">
|
|
تاریخ ایجاد: {{$t->created_at ? Jalalian::fromCarbon(Carbon::parse($t->created_at))->format('Y/m/d') : ''}}
|
|
</p>
|
|
@if($t->total_duration !== '00:00:00')
|
|
<p class="mt-2 text-gray-600">
|
|
مجموع زمان صرف شده: {{$t->total_duration}}
|
|
</p>
|
|
|
|
@endif
|
|
|
|
@php
|
|
$task_items = $sub_work_items->where('parent',$t->task_id)
|
|
@endphp
|
|
@foreach($task_items as $item)
|
|
<div class=" form w-[350px] text-center border-gray-300 border-2 border-dotted max-w-80 mt-2"
|
|
>
|
|
<style>
|
|
.form ul li {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 8px;
|
|
text-align: right;
|
|
}
|
|
|
|
.form ul li input[type="checkbox"] {
|
|
margin-top: 3px;
|
|
accent-color: #3b82f6; /* آبی Tailwind */
|
|
}
|
|
|
|
.form ul li p {
|
|
margin: 0;
|
|
}
|
|
</style>
|
|
{{-- {{$t}}--}}
|
|
<a onclick="openTaskModal(
|
|
'{{ $item->task_id }}',
|
|
'{{ $item->p_id ?? '' }}',
|
|
'{{ $item->started_at ?? '' }}',
|
|
'{{ $item->ended_at ?? '' }}',
|
|
'{{ $item->ended_at ? 'start' : ($item->started_at ? 'end' : 'start') }}'
|
|
)"
|
|
class="relative flex items-center justify-center w-full text-center py-2
|
|
font-bold text-base rounded hover:bg-gray-500 hover:text-white transition cursor-pointer">
|
|
<span class="">{{ $item->name }}</span>
|
|
</a>
|
|
|
|
|
|
@if(isset($t->description_html) && strlen(trim(strip_tags($item->description_html))) > 0)
|
|
<p class="mt-2 text-gray-600">
|
|
توضیحات: {!! $item->description_html !!}
|
|
</p>
|
|
@endif
|
|
@if(isset($item->start_date))
|
|
<lable class="mt-2 text-gray-600">
|
|
تاریخ شروع: {{$item->start_date}}
|
|
</lable>
|
|
@endif
|
|
@if(isset($item->target_date))
|
|
<p class="mt-2 text-gray-600">
|
|
تاریخ
|
|
پایان: {{$item->target_date ? Jalalian::fromCarbon(Carbon::parse($item->target_date))->format('Y/m/d') : ''}}
|
|
</p>
|
|
@endif
|
|
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@endforeach
|
|
</div>
|
|
@else
|
|
<div class=" mt-[200px]">
|
|
<h1 class=" text-xl font-bold" style="color: #959595">وظیفه ای ندارید</h1>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
|
|
|
|
{{-- START TASK MODAL --}}
|
|
<div id="taskModal" class="fixed inset-0 bg-black/40 hidden items-center justify-center z-50">
|
|
<div class="bg-white w-[350px] rounded-2xl shadow-lg p-5 text-center">
|
|
<h2 class="text-lg font-bold mb-3" id="modalTitle">وضعیت وظیفه</h2>
|
|
<p class="text-gray-600 mb-4" id="modalDesc"></p>
|
|
|
|
<div class="flex justify-center gap-3">
|
|
<button id="actionBtn"
|
|
class="px-4 py-2 rounded-lg font-semibold text-white bg-blue-600 hover:bg-blue-700 transition">
|
|
شروع
|
|
</button>
|
|
<button id="cancelBtn"
|
|
class="px-4 py-2 rounded-lg font-semibold bg-gray-300 hover:bg-gray-400 transition">
|
|
انصراف
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
@section('script')
|
|
<script>
|
|
let currentTask = {};
|
|
|
|
function openTaskModal(taskId, p_id, started_at, ended_at, actionType) {
|
|
currentTask = {taskId, p_id, started_at, ended_at, actionType};
|
|
|
|
const modal = document.getElementById('taskModal');
|
|
const actionBtn = document.getElementById('actionBtn');
|
|
const modalTitle = document.getElementById('modalTitle');
|
|
const modalDesc = document.getElementById('modalDesc');
|
|
|
|
// تعیین متن دکمه بر اساس actionType
|
|
actionBtn.textContent = actionType === 'start' ? 'شروع' : 'پایان';
|
|
if (actionType === 'start') {
|
|
actionBtn.classList.remove('bg-green-600', 'hover:bg-green-700');
|
|
actionBtn.classList.add('bg-blue-600', 'hover:bg-blue-700');
|
|
modalDesc.textContent = 'آیا میخواهید این وظیفه را شروع کنید؟';
|
|
} else {
|
|
actionBtn.classList.remove('bg-blue-600', 'hover:bg-blue-700');
|
|
actionBtn.classList.add('bg-green-600', 'hover:bg-green-700');
|
|
modalDesc.textContent = 'آیا میخواهید این وظیفه را پایان دهید؟';
|
|
}
|
|
|
|
modal.classList.remove('hidden');
|
|
modal.classList.add('flex');
|
|
|
|
// عملکرد دکمه شروع/پایان
|
|
actionBtn.onclick = () => handleTaskAction();
|
|
document.getElementById('cancelBtn').onclick = () => closeModal();
|
|
}
|
|
|
|
function closeModal() {
|
|
const modal = document.getElementById('taskModal');
|
|
modal.classList.add('hidden');
|
|
modal.classList.remove('flex');
|
|
}
|
|
|
|
function handleTaskAction() {
|
|
// ثبت زمان فعلی با فرمت Y-m-d H:i:s
|
|
const now = new Date();
|
|
const pad = n => n.toString().padStart(2, '0');
|
|
const formattedNow = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
|
|
|
|
if (currentTask.actionType === 'start') {
|
|
currentTask.started_at = formattedNow;
|
|
} else {
|
|
currentTask.ended_at = formattedNow;
|
|
}
|
|
|
|
// مسیر API لاراول که باید POST بزنی
|
|
fetch('{{ url("/task-manager") }}', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
|
},
|
|
body: JSON.stringify({
|
|
task_id: currentTask.taskId,
|
|
p_id: currentTask.p_id,
|
|
started_at: currentTask.started_at,
|
|
ended_at: currentTask.ended_at,
|
|
action_type: currentTask.actionType
|
|
})
|
|
})
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
console.log('Task updated', data);
|
|
closeModal();
|
|
} else {
|
|
alert('خطا در انجام عملیات!');
|
|
}
|
|
})
|
|
.catch(err => {
|
|
console.error(err);
|
|
alert('خطا در ارتباط با سرور!');
|
|
});
|
|
}
|
|
|
|
function togglerequests(elementId) {
|
|
document.getElementById(elementId).classList.toggle('hidden');
|
|
}
|
|
</script>
|
|
|
|
@endsection
|