1212 lines
63 KiB
PHP
Executable File
1212 lines
63 KiB
PHP
Executable File
<?php
|
|
|
|
use App\Models\Attendance;
|
|
use App\Models\User;
|
|
use App\Models\ai;
|
|
use Morilog\Jalali\Jalalian;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Collection;
|
|
|
|
|
|
if (!empty($user->tasks)) {
|
|
$in_progress = '#fca000';
|
|
$todo = '#7d7d7d';
|
|
$error = '#fc0000';
|
|
$backlog = '#bababa';
|
|
$done = '#40de02';
|
|
$cancelled = 'black';
|
|
|
|
$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
|
|
];
|
|
$state_order = [
|
|
"c73c2044-ea14-42cb-b08d-cecf3d1fdfb5",
|
|
"a9ce312f-cfca-491e-8e3d-1975aa6ebc10",
|
|
"dea1fb57-a281-4fe7-8f3e-ee5567637e35",
|
|
"770fbe42-99f6-41db-9b9e-773d9cced1a5",
|
|
"b0e464e1-34eb-41ea-b2f7-3ef7483bc9f0",
|
|
"d61d14a3-72f7-4f44-894b-efe8b2a75be1",
|
|
];
|
|
|
|
$user->tasks = $user->tasks->sortBy(function ($task) use ($state_order) {
|
|
return array_search($task->state, $state_order);
|
|
});
|
|
}
|
|
//dd(count($break = $user->attendanceBreaks));
|
|
if (count($user->attendanceBreaks) > 0) {
|
|
$break = $user->attendanceBreaks[0];
|
|
if ($break->break_end == null) {
|
|
$now = Carbon::now()->format('Y-m-d H:i:s');
|
|
$attendances = new Attendance();
|
|
$duration = $attendances->duration($break->break_start, $now);
|
|
}
|
|
}
|
|
//dd($now, $break->break_start, $duration);
|
|
|
|
|
|
?>
|
|
@extends('app')
|
|
@section('content')
|
|
|
|
<div class="container flex-col"
|
|
style="letter-spacing: 0;display: flex;justify-content: center;align-items: center; margin : 90px 0 10px 0">
|
|
|
|
|
|
{{-- <button type="button"--}}
|
|
{{-- class="fixed max-w-[350px] bottom-24 right-9 z-50--}}
|
|
{{-- w-16 h-16 flex items-center justify-center--}}
|
|
{{-- text-white rounded-full--}}
|
|
{{-- bg-blue-500 hover:bg-blue-600--}}
|
|
{{-- shadow-lg cursor-pointer transition-all duration-300"--}}
|
|
{{-- onclick="openModal('ثبت روز کاری جدید', 'new')">--}}
|
|
{{-- ثبت روز جدید--}}
|
|
{{-- </button>--}}
|
|
@if (!isset($_COOKIE['token-0']))
|
|
|
|
<form id="attendanceForm" class="form items-center" action="{{ url('attendance/enter') }}" method="post"
|
|
style="text-align: left">
|
|
@csrf
|
|
<p class="title text-center font-bold text-lg mb-2">سامانه گذارش کار</p>
|
|
<p class="message text-right text-sm text-gray-700">{{ $s->response }}</p>
|
|
|
|
@php
|
|
$user_identity = $_COOKIE['user_identity'] ?? '';
|
|
@endphp
|
|
|
|
<input type="hidden" name="latitude" id="latitude">
|
|
<input type="hidden" name="longitude" id="longitude">
|
|
<input type="hidden" name="distance" id="distance">
|
|
|
|
<p id="distanceMessage" class="text-center mb-2 font-semibold text-gray-600">در حال بررسی موقعیت...</p>
|
|
|
|
<button id="submitBtn" disabled type="button"
|
|
class="bg-gray-400 text-white rounded cursor-not-allowed rounded-xl py-2 px-4 max-w-60 self-center"
|
|
style="width: 100%">
|
|
ورود/خروج
|
|
</button>
|
|
|
|
<div id="output" class="text-red-500 text-sm mt-2 text-center"></div>
|
|
|
|
<div class="flex justify-flex max-w-[240px]" style="align-items: center;">
|
|
<button type="button"
|
|
class="w-1/2 p-2 text-sm text-white text-center rounded-xl bg-cyan-500 hover:bg-cyan-600 cursor-pointer"
|
|
onclick="openModal('ثبت روز کاری جدید', 'new')">
|
|
ثبت روز کاری
|
|
</button>
|
|
|
|
<button type="button" id="breakAttendance"
|
|
class="w-1/2 p-2 text-sm text-white text-center rounded-xl bg-cyan-500 hover:bg-cyan-600
|
|
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 cursor-pointer mx-auto"
|
|
href="">
|
|
استراحت
|
|
</button>
|
|
</div>
|
|
<button type="button" id="tasksBtn"
|
|
class="text-white rounded-xl py-2 px-4 max-w-60 self-center bg-cyan-500 hover:bg-cyan-700 cursor-pointer w-full"
|
|
onclick="openTaskModal()">
|
|
وظایف
|
|
</button>
|
|
{{--<p>{{Carbon::now()}}</p>--}}
|
|
</form>
|
|
{{-- @if(session('open_task_modal'))--}}
|
|
{{-- <script>--}}
|
|
{{-- window.onload = () => {--}}
|
|
{{-- openTaskModal();--}}
|
|
{{-- };--}}
|
|
{{-- </script>--}}
|
|
{{-- @endif--}}
|
|
|
|
@else
|
|
|
|
<div class="bg-white flex justify-flex p-4 rounded-xl max-w-[350px] flex-col items-center">
|
|
|
|
|
|
<label class="text-xl font-bold pb-2">
|
|
{{$user->name}}
|
|
</label>
|
|
|
|
<button type="button"
|
|
class="w-1/2 p-2 text-sm text-white text-center rounded-xl bg-cyan-500 hover:bg-cyan-600 cursor-pointer"
|
|
onclick="openModal('ثبت روز کاری جدید', 'new')">
|
|
ثبت روز کاری
|
|
</button>
|
|
|
|
|
|
</div>
|
|
@endif
|
|
|
|
|
|
|
|
<div class="w-full flex justify-center mt-4 pb-20" style="">
|
|
<div class="overflow-hidden rounded-[23px] max-w-[350px]">
|
|
<div class=" border-b border-gray-300 text-center w-full">
|
|
|
|
|
|
<!-- Your Table Code Here -->
|
|
<div class="w-[350px]">
|
|
|
|
@if(isset($_COOKIE['user_identity']))
|
|
{{-- قسمت پردازش دادهها: گروهبندی لیست حضور و غیاب بر اساس نام ماه شمسی --}}
|
|
@php
|
|
// بررسی وجود داده
|
|
$attendances = $user->attendances ?? collect();
|
|
|
|
// گروهبندی دادهها بر اساس نام ماه (مثلا: مهر، آبان)
|
|
$groupedData = $attendances->groupBy(function($item) {
|
|
return \Morilog\Jalali\Jalalian::fromCarbon(\Carbon\Carbon::parse($item->entered_at))->format('%B');
|
|
});
|
|
@endphp
|
|
|
|
<div class="container inline-flex flex-col items-center justify-center">
|
|
@if($groupedData->isEmpty())
|
|
<div class="mt-80 text-gray-500 text-xl font-bold italic">
|
|
<h1>اطلاعاتی موجود نمیباشد</h1>
|
|
</div>
|
|
@else
|
|
{{-- دکمههای تب (نام ماهها) --}}
|
|
<div class="tab rounded-t-2xl max-w-[350px] mx-auto flex overflow-x-auto"
|
|
style="margin-top: 0px; max-width: 350px">
|
|
@foreach($groupedData->keys() as $month)
|
|
<button class="tablinks rounded-t-2xl cursor-pointer px-4 py-2 hover:bg-gray-200 transition flex-shrink-0"
|
|
onclick="openCity(event, '{{$month}}')">
|
|
{{$month}}
|
|
</button>
|
|
@endforeach
|
|
</div>
|
|
|
|
{{-- محتوای تبها (جدولها) --}}
|
|
@foreach($groupedData as $month => $records)
|
|
<div id="{{$month}}"
|
|
class="tabcontent w-[350px] bg-white rounded-b-xl rounded-tl-2xl cursor-default leading-7 shadow-md">
|
|
|
|
<table class="table-auto"
|
|
style="width:100%; border-collapse: collapse; text-align: center">
|
|
<thead>
|
|
<tr style="border-bottom: 1px solid #ddd; background: rgba(244,244,244,0.82);"
|
|
class="border-1 border-slate-300">
|
|
@if($_COOKIE['user_identity'] == 1370)
|
|
<th style="border-right: 1px solid #ddd; padding: 8px;">نام</th>
|
|
@endif
|
|
<th style="border-right: 1px solid #ddd; padding: 4px;">تاریخ</th>
|
|
<th style="border-right: 1px solid #ddd; padding: 4px;">ورود</th>
|
|
<th style="border-right: 1px solid #ddd; padding: 4px;">خروج</th>
|
|
<th style="border-right: 1px solid #ddd; padding: 4px;">مدت</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tbody>
|
|
@foreach($records as $item)
|
|
<tr class="hover:bg-cyan-500 cursor-pointer transition duration-150"
|
|
style="border-bottom: 1px solid #ddd; background-color: {{$item->requested ? '#bfdbfe' : '#ffffff' }}"
|
|
onclick="openModal('{{ $item->id }}', '{{ $item->id }}' , '{{ $item->entered_at }}', '{{ $item->exited_at }} ')">
|
|
|
|
{{-- شرط نمایش نام --}}
|
|
@if($_COOKIE['user_identity'] == 1370)
|
|
<td style="border-right: 1px solid #ddd; padding: 8px;">
|
|
{{$item->user_identity}}
|
|
</td>
|
|
@endif
|
|
|
|
{{-- تاریخ --}}
|
|
<td style="border-right: 1px solid #ddd; padding: 4px; background-color: {{"#e6e6e6" }};">
|
|
{{ $item->entered_at ? \Morilog\Jalali\Jalalian::fromCarbon(\Carbon\Carbon::parse($item->entered_at))->format('m/d') : '-' }}
|
|
<span class="text-xs text-gray-500 block">
|
|
{{ $item->entered_at ? \Morilog\Jalali\Jalalian::fromCarbon(\Carbon\Carbon::parse($item->entered_at))->format('%A') : '' }}
|
|
</span>
|
|
</td>
|
|
|
|
{{-- زمان ورود --}}
|
|
<td style="border-right: 1px solid #ddd; padding: 4px; background-color: {{$item->entered_at && $item->distance ? ($item->requested !== null ? '#fad1d1' :($item->distance < 50 ? '#d1fae5' : '#edae80')) : '' }};">
|
|
{{ $item->entered_at ? \Carbon\Carbon::parse($item->entered_at)->format('H:i') : '-' }}
|
|
</td>
|
|
|
|
{{-- زمان خروج --}}
|
|
<td style="border-right: 1px solid #ddd; padding: 4px; background-color: {{$item->exited_at && $item->distance_exit ? ($item->requested !== null ? '#fad1d1' :($item->distance_exit < 50 ? '#d1fae5' : '#edae80')) : '' }};">
|
|
{{ $item->exited_at ? \Carbon\Carbon::parse($item->exited_at)->format('H:i') : '-' }}
|
|
</td>
|
|
|
|
{{-- مدت زمان --}}
|
|
<td style="border-right: 1px solid #ddd; padding: 4px;">
|
|
{{ $item->entered_at && $item->exited_at ? \Carbon\Carbon::parse($item->duration)->format('H:i') : '-' }}
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
|
|
{{-- ردیف جمع کل (اختیاری - چون متغیر آن موجود نبود کامنت کردم که خطا ندهد) --}}
|
|
|
|
<tr>
|
|
<td colspan="5" class="rounded-b-xl bg-gray-50 font-bold"
|
|
style="border-top: 1px solid #ddd; text-align: center; padding: 10px;">
|
|
تعداد رکورد: {{ count($records) }}
|
|
</td>
|
|
</tr>
|
|
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@endforeach
|
|
@endif
|
|
</div>
|
|
|
|
|
|
@endif
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- ATTENDANCE Modal -->
|
|
<div id="modal-container"
|
|
class="fixed inset-0 z-50 hidden bg-black bg-opacity-60 flex items-center justify-center p-4">
|
|
<div id="modal-content" class=" bg-white p-4 sm:p-6 rounded-lg shadow-lg max-w-sm w-full relative">
|
|
<h2 id="modal-title" class="text-xl sm:text-2xl font-semibold mb-4 text-center"></h2>
|
|
<p id="modal-body" class="text-gray-700 mb-4 text-center"></p>
|
|
<div class="flex flex-col gap-4" style="align-items: center">
|
|
|
|
<div class="flex justify-center gap-2">
|
|
<div id="panel-access-link" href="#" class="" title="Panel Access"></div>
|
|
</div>
|
|
|
|
<form id="edit-form" method="post" action="{{$formaction.'edit'}}"
|
|
class="inline-block flex-col gap-2 flex items-center">
|
|
@csrf
|
|
|
|
<p id="new-date-label" style="display: none; text-align: right; ">تاریخ:</p>
|
|
<div id="new-date-group" class="input-group" style="margin: 20px; display: none;">
|
|
<input type="text" name="display_date" id="display_date"
|
|
class=" example1 form-control border p-2 rounded date-picker-input" value=""
|
|
placeholder="تاریخ"
|
|
readonly
|
|
>
|
|
|
|
</div>
|
|
|
|
<p style=" ">ساعت شروع:</p>
|
|
<div class="input-group clockpicker border-2 border-gray-300 rounded-lg"
|
|
style="margin: 20px;">
|
|
<span class="input-group-addon bg-gray-200 align-middle text-stone-600 rounded-r-md p-2 pt-2.5">
|
|
<i class="fa-solid fa-clock"></i>
|
|
</span>
|
|
<input type="text" name="starttime" id="starttime"
|
|
class="form-control cursor-default p-2 w-36 "
|
|
placeholder="09:00"
|
|
value=""
|
|
readonly
|
|
>
|
|
<button type="button" onclick="clearTime('starttime')"
|
|
class="p-2 bg-gray-200 hover:bg-gray-300 text-red-600 rounded-l-md w-9
|
|
title=" خالی کردن ساعت
|
|
">
|
|
×
|
|
</button>
|
|
</div>
|
|
|
|
<p>ساعت پایان:</p>
|
|
<div class="input-group clockpicker border-2 border-gray-300 rounded-lg"
|
|
style="margin: 20px;">
|
|
<span class="input-group-addon bg-gray-200 align-middle text-stone-600 rounded-r-md p-2 pt-2.5">
|
|
<i class="fa-solid fa-clock"></i>
|
|
</span>
|
|
<input type="text" name="endtime" id="endtime"
|
|
class="form-control cursor-default p-2 w-36"
|
|
placeholder="17:30"
|
|
value=""
|
|
readonly
|
|
>
|
|
|
|
|
|
<button type="button" onclick="clearTime('endtime')"
|
|
class="p-2 bg-gray-200 hover:bg-gray-300 text-red-600 rounded-l-md w-9
|
|
title=" خالی کردن ساعت
|
|
">
|
|
×
|
|
</button>
|
|
</div>
|
|
|
|
<input type="hidden" name="uname" id="uname" value="{{$user->user_name ?? null}}">
|
|
<input type="hidden" name="date" id="date" value="">
|
|
<input type="hidden" name="id" id="edit_id" value="">
|
|
|
|
<button type="submit" id="submit-edit-button" style="display: none;"
|
|
onclick="return confirmSubmit()">
|
|
ثبت تغییرات
|
|
</button>
|
|
</form>
|
|
|
|
<form id="delete-form" action="{{$formaction.'delete'}}" method="post" style="display: none;">
|
|
@csrf
|
|
<input type="hidden" name="id" id="delete_id" value="">
|
|
<button type="submit" id="submit-delete-button" onclick="return confirmSubmit()">
|
|
حذف
|
|
</button>
|
|
</form>
|
|
|
|
|
|
<div class="flex justify-center gap-2 mt-2 px-4">
|
|
|
|
<button type="button" class="bg-blue-500 text-white rounded p-2 **w-[70%]**"
|
|
onclick="document.getElementById('edit-form').submit(); return confirmSubmit()">
|
|
@if(isset($_COOKIE['ad']) && $_COOKIE['ad'] == 1)
|
|
ثبت تغییرات
|
|
@else
|
|
ارسال برای تایید
|
|
@endif
|
|
</button>
|
|
|
|
<button type="button" class="bg-red-500 text-white rounded p-2 **w-[30%]**"
|
|
onclick="document.getElementById('delete-form').submit(); return confirmSubmit()">
|
|
<i class="fas fa-trash text-white text-lg"></i>
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
{{-- START TASK MODAL --}}
|
|
<div id="taskModal"
|
|
class="hidden fixed inset-0 bg-black/40 items-start justify-center z-50 flex backdrop-blur-sm scroll-auto pt-10"
|
|
onclick="closeOnOutsideClick(event)">
|
|
<div class="relative bg-white w-[350px] rounded-2xl shadow-lg p-5 text-center">
|
|
<button onclick="closeTaskModal()"
|
|
class="absolute top-3 right-3 text-gray-400 hover:text-gray-600 transition">
|
|
<i class="fa-solid fa-xmark"></i>
|
|
</button>
|
|
|
|
<h2 class="text-lg font-bold mb-3" id="modalTitle">انتخاب وظیفه</h2>
|
|
|
|
<p class="text-gray-600 mb-4" id="modalDesc">یکی از وظایف زیر را انتخاب کنید:</p>
|
|
<input class="h-12 w-full bg-transparent pl-11 pr-4 text-sm text-custom-text-100
|
|
placeholder:text-custom-text-400 focus:ring-0 rounded-3xl border-2 border-gray-300 py-2"
|
|
placeholder="جست و جو..." tabindex="1" id="headlessui-combobox-input-:r13m:" role="combobox"
|
|
aria-expanded="false" aria-autocomplete="list" data-headlessui-state="" type="text" value=""
|
|
aria-controls="headlessui-combobox-options-:r13n:"
|
|
aria-activedescendant="headlessui-combobox-option-:r13s:" data-sharkid="__4">
|
|
|
|
{{-- <div class="grid flex-col gap-2 grid-cols-2 pb-3 items-center justify-items-end">--}}
|
|
@if(isset($user->tasks) && count($user->tasks) >= 1)
|
|
|
|
<form action="{{url("active_task")}}" method="POST" class=" ">@csrf
|
|
{{-- <input type="hidden" name="pid" value="{{ $user->tasks->pivot->id }}" class="">--}}
|
|
<input type="hidden" name="uid" value="{{ $user->id }}" class="">
|
|
<div class=" overflow-y-scroll"
|
|
style="max-height: calc(100vh - 300px);">
|
|
@foreach($user->tasks as $item)
|
|
<div class="inline-flex items-center bg-gray-300 hover:bg-cyan-600 rounded-lg m-2 p-2 justify-between"
|
|
style="display: flex">
|
|
@if($user->active_task)
|
|
@if( $user->active_task == $item->title )
|
|
<input type="radio" name="task_id" checked="true"
|
|
value="{{ $item->id }}"
|
|
class="">
|
|
|
|
@else
|
|
<input type="radio" name="task_id" value="{{ $item->id }}" class=""
|
|
disabled>
|
|
|
|
@endif
|
|
@else
|
|
<input type="radio" name="task_id" value="{{ $item->id }}" class="">
|
|
|
|
{{-- <input type="hidden" name="task_name" value="{{$item->name}}">--}}
|
|
@endif
|
|
|
|
<div class="px-2.5" style="direction: rtl">{{ $item->title }}</div>
|
|
<span class="block h-1.5 w-1.5 flex-shrink-0 rounded-full" style="background-color:
|
|
{!! array_key_exists($item->state,$state) ? $state[$item->state] : "" !!};"></span>
|
|
|
|
</div>
|
|
|
|
@endforeach
|
|
</div>
|
|
@if( $user->active_task )
|
|
{{-- <div class="absolute bottom-2 left-0 w-full flex justify-center">--}}
|
|
<button class="submit mt-2">
|
|
پایان
|
|
</button>
|
|
{{-- </div>--}}
|
|
@else
|
|
{{-- <div class="absolute bottom-2 left-0 w-full flex justify-center">--}}
|
|
<button class="submit mt-2">
|
|
شروع
|
|
</button>
|
|
{{-- </div>--}}
|
|
@endif
|
|
|
|
</form>
|
|
@else
|
|
<div class="inline-flex justify-center items-center"
|
|
style="height: calc(100vh - 400px);">
|
|
<p class="font-bold text-gray-400">
|
|
وظیفه ای وجود ندارد
|
|
</p>
|
|
</div>
|
|
@endif
|
|
{{-- افزودن تسک--}}
|
|
<form>
|
|
<input class="h-12 w-[200px] bg-transparent pl-11 pr-4 text-sm text-custom-text-100
|
|
placeholder:text-custom-text-400 focus:ring-0 rounded-3xl border-2 border-gray-300 py-2"
|
|
placeholder="عنوان وظیفه" tabindex="1" id="taskTitle" role="combobox"
|
|
aria-expanded="false" aria-autocomplete="list" data-headlessui-state="" type="text" value=""
|
|
aria-controls="headlessui-combobox-options-:r13n:"
|
|
aria-activedescendant="headlessui-combobox-option-:r13s:" data-sharkid="__4">
|
|
<button id="createTask"
|
|
class="mt-4 inline-block bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-2.5 fa-notdog fa-solid fa-plus rounded-full">
|
|
</button>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
@endsection
|
|
|
|
@section('script')
|
|
<script>
|
|
|
|
const existed = {{ $existed ? 'true' : 'false' }};
|
|
{{--const today = {{$today}};--}}
|
|
const distanceMessage = document.getElementById("distanceMessage");
|
|
|
|
|
|
const referenceLat = 32.6504751;
|
|
const referenceLng = 51.6936045;
|
|
|
|
const submitBtn = document.getElementById("submitBtn");
|
|
const latInput = document.getElementById("latitude");
|
|
const lngInput = document.getElementById("longitude");
|
|
const distanceInput = document.getElementById("distance");
|
|
const form = document.getElementById("attendanceForm");
|
|
// naser
|
|
if (existed) {
|
|
submitBtn.textContent = "خروج";
|
|
} else {
|
|
submitBtn.textContent = "ورود";
|
|
}
|
|
|
|
|
|
function getDistanceInMeters(lat1, lon1, lat2, lon2) {
|
|
const earthRadius = 6371000; // meters
|
|
const toRad = deg => deg * Math.PI / 180;
|
|
const dLat = toRad(lat2 - lat1);
|
|
const dLon = toRad(lon2 - lon1);
|
|
lat1 = toRad(lat1);
|
|
lat2 = toRad(lat2);
|
|
const a = Math.sin(dLat / 2) ** 2 +
|
|
Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) ** 2;
|
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
return earthRadius * c;
|
|
}
|
|
|
|
navigator.geolocation.getCurrentPosition(
|
|
position => {
|
|
const lat = position.coords.latitude;
|
|
const lng = position.coords.longitude;
|
|
|
|
latInput.value = lat;
|
|
lngInput.value = lng;
|
|
|
|
const dist = Math.round(getDistanceInMeters(referenceLat, referenceLng, lat, lng));
|
|
distanceInput.value = dist;
|
|
if (dist < 20) {
|
|
distanceMessage.textContent = `مکان: شرکت`;
|
|
} else {
|
|
distanceMessage.textContent = `مکان: خارج از شرکت`;
|
|
}
|
|
|
|
distanceMessage.classList.remove("bg-gray-400", "bg-blue-500", "bg-green-500", "bg-orange-500", "cursor-not-allowed");
|
|
if (dist < 10) {
|
|
distanceMessage.classList.add("text-green-500");
|
|
} else if (dist < 50) {
|
|
distanceMessage.classList.add("text-blue-500");
|
|
} else if (dist > 2000) {
|
|
distanceMessage.classList.add("text-orange-500");
|
|
} else {
|
|
distanceMessage.classList.add("text-gray-400");
|
|
}
|
|
submitBtn.disabled = false;
|
|
submitBtn.classList.remove("bg-gray-400", "cursor-not-allowed");
|
|
submitBtn.classList.add("bg-cyan-500", "hover:bg-cyan-700", "cursor-pointer");
|
|
|
|
},
|
|
error => {
|
|
const lat = 32.6520532791536; // از مختصات ثابت استفاده کنید
|
|
const lng = 51.68472614422439; // از مختصات ثابت استفاده کنید
|
|
|
|
const dist = Math.round(getDistanceInMeters(referenceLat, referenceLng, lat, lng));
|
|
distanceInput.value = dist;
|
|
distanceMessage.textContent = `مکان: خارج از شرکت`;
|
|
|
|
distanceMessage.classList.remove("bg-gray-400", "bg-blue-500", "bg-green-500", "bg-orange-500", "cursor-not-allowed");
|
|
distanceMessage.classList.add("text-orange-500");
|
|
submitBtn.disabled = false;
|
|
submitBtn.classList.remove("bg-gray-400", "cursor-not-allowed");
|
|
submitBtn.classList.add("bg-cyan-500", "hover:bg-cyan-700", "cursor-pointer");
|
|
|
|
// alert("⛔ خطا در دریافت موقعیت مکانی: " + error.message), {
|
|
// enableHighAccuracy: true,
|
|
// timeout: 10000,
|
|
// maximumAge: 0
|
|
}
|
|
);
|
|
const attendanceForm = document.getElementById('attendanceForm');
|
|
|
|
const output = document.getElementById('output');
|
|
const challenge = new Uint8Array(32);
|
|
window.crypto.getRandomValues(challenge);
|
|
const createOptions = {
|
|
challenge,
|
|
rp: {
|
|
name: "مثال سایت شما"
|
|
},
|
|
user: {
|
|
id: Uint8Array.from('user-id', c => c.charCodeAt(0)),
|
|
name: "user@example.com",
|
|
displayName: "نام کاربر"
|
|
},
|
|
pubKeyCredParams: [{
|
|
type: 'public-key',
|
|
alg: -7
|
|
}],
|
|
authenticatorSelection: {
|
|
authenticatorAttachment: "platform",
|
|
userVerification: "required"
|
|
},
|
|
timeout: 60000,
|
|
attestation: "direct"
|
|
};
|
|
submitBtn.addEventListener('click', async () => {
|
|
// ابتدا اعتبارسنجی اثر انگشت توسط WebAuthn
|
|
if (!window.PublicKeyCredential) {
|
|
alert('مرورگر شما از احراز هویت بیومتریک پشتیبانی نمیکند.');
|
|
return;
|
|
}
|
|
try {
|
|
const credential = await navigator.credentials.create({
|
|
publicKey: createOptions
|
|
});
|
|
attendanceForm.submit();
|
|
} catch (error) {
|
|
output.textContent = error.name === 'NotAllowedError' ? 'احراز هویت لغو شد یا دسترسی مجاز نبود.' : 'عملیات ناموفق بود. لطفاً دوباره امتحان کنید.';
|
|
}
|
|
});
|
|
|
|
|
|
|
|
function openCity(evt, Month) {
|
|
var i, tabcontent, tablinks;
|
|
// مخفی کردن تمام محتواها
|
|
tabcontent = document.getElementsByClassName("tabcontent");
|
|
for (i = 0; i < tabcontent.length; i++) {
|
|
tabcontent[i].style.display = "none";
|
|
}
|
|
|
|
// غیرفعال کردن تمام تبها
|
|
tablinks = document.getElementsByClassName("tablinks");
|
|
for (i = 0; i < tablinks.length; i++) {
|
|
tablinks[i].className = tablinks[i].className.replace(" active bg-gray-300 font-bold", "");
|
|
// اضافه کردن استایل دیفالت اگر کلاس اکتیو حذف شد
|
|
if (!tablinks[i].className.includes("active")) {
|
|
tablinks[i].style.backgroundColor = "";
|
|
}
|
|
}
|
|
|
|
// نمایش تب انتخاب شده
|
|
document.getElementById(Month).style.display = "block";
|
|
evt.currentTarget.className += " active bg-gray-300 font-bold";
|
|
}
|
|
|
|
// باز کردن اولین تب به صورت خودکار هنگام لود صفحه
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
let firstTab = document.querySelector(".tablinks");
|
|
if (firstTab) {
|
|
firstTab.click();
|
|
}
|
|
});
|
|
|
|
{{-- TASKS MODAL--}}
|
|
function openTaskModal(task) {
|
|
const modal = document.getElementById('taskModal');
|
|
modal.classList.remove('hidden');
|
|
modal.classList.add('flex');
|
|
|
|
// آپدیت متن دکمه بر اساس وضعیت تسک
|
|
updateStatusButtonText(task.started_at, task.ended_at);
|
|
|
|
// تنظیم عملکرد دکمه بر اساس تسک فعلی
|
|
const statusBtn = document.getElementById('statusBtn');
|
|
statusBtn.onclick = () => handleTaskAction(
|
|
task.id,
|
|
task.p_id,
|
|
task.started_at,
|
|
task.ended_at
|
|
);
|
|
}
|
|
|
|
// -------------------------------
|
|
// بستن مودال
|
|
// -------------------------------
|
|
function closeTaskModal() {
|
|
const modal = document.getElementById('taskModal');
|
|
modal.classList.add('hidden');
|
|
modal.classList.remove('flex');
|
|
}
|
|
|
|
function closeOnOutsideClick(event) {
|
|
// وقتی کاربر بیرون از محتوای مودال کلیک کنه، ببندش
|
|
if (event.target.id === 'taskModal') {
|
|
closeTaskModal();
|
|
}
|
|
}
|
|
|
|
// -------------------------------
|
|
// آپدیت متن دکمه شروع/پایان
|
|
// -------------------------------
|
|
function updateStatusButtonText(started_at, ended_at) {
|
|
const statusBtn = document.getElementById('statusBtn');
|
|
let text = "شروع";
|
|
|
|
if (started_at && !ended_at) {
|
|
text = "پایان";
|
|
}
|
|
|
|
statusBtn.textContent = text;
|
|
}
|
|
|
|
// -------------------------------
|
|
// هندل عملیات شروع / پایان تسک
|
|
// -------------------------------
|
|
function handleTaskAction(taskId, p_id, started_at, ended_at) {
|
|
// ... (منطق تعیین actionType و زمانها) ...
|
|
|
|
// ارسال داده به سرور
|
|
fetch('{{ url("/task-manager") }}', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
|
},
|
|
body: JSON.stringify({
|
|
task_id: taskId,
|
|
p_id: p_id,
|
|
started_at: started_at,
|
|
ended_at: ended_at,
|
|
action_type: actionType
|
|
})
|
|
})
|
|
.then(res => {
|
|
// ابتدا بررسی وضعیت HTTP
|
|
if (!res.ok) {
|
|
// اگر کد وضعیت 4xx یا 5xx باشد
|
|
throw new Error(`HTTP error! status: ${res.status}`);
|
|
}
|
|
// در صورت موفقیت (200)، تلاش برای خواندن JSON
|
|
return res.json();
|
|
})
|
|
.then(data => {
|
|
// 💡 اصلاح: بررسی دقیق فیلد success
|
|
if (data && data.success === true) {
|
|
console.log('✅ Task updated successfully:', data);
|
|
closeTaskModal();
|
|
// 💡 رفع مشکل عدم بهروزرسانی وضعیت دکمه در بار بعدی:
|
|
// برای سادگی، صفحه را رفرش کنید تا دادههای جدید واکشی شوند.
|
|
window.location.reload();
|
|
} else {
|
|
// سرور با کد 200 جواب داده اما success: false بوده یا ساختار پاسخ مشکل دارد.
|
|
console.error('❌ Operation failed based on server data:', data);
|
|
alert('❌ خطا در انجام عملیات! پاسخ سرور را در کنسول بررسی کنید.');
|
|
}
|
|
})
|
|
.catch(err => {
|
|
// شامل خطای ارتباط، خطای HTTP و خطای JSON نامعتبر
|
|
console.error('⚠️ Server or JSON parsing error:', err);
|
|
alert(`⚠️ خطا در ارتباط با سرور یا پردازش داده!`);
|
|
});
|
|
}
|
|
|
|
//SEARCH BAR IN TASK MODAL
|
|
const searchInput = document.getElementById("headlessui-combobox-input-:r13m:");
|
|
const listItems = document.querySelectorAll('#taskModal .inline-flex.items-center');
|
|
|
|
searchInput.addEventListener("input", function () {
|
|
const filter = searchInput.value.toLowerCase();
|
|
listItems.forEach(item => {
|
|
const nameDiv = item.querySelector('div');
|
|
if (nameDiv) {
|
|
const name = nameDiv.textContent.toLowerCase();
|
|
if (name.includes(filter)) {
|
|
item.style.display = 'flex';
|
|
} else {
|
|
item.style.display = 'none';
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
const taskTitle = document.getElementById('taskTitle');
|
|
|
|
function createTask(taskTitle) {
|
|
// const createTask = document.getElementById('createTask');
|
|
|
|
|
|
if (createTask) {
|
|
createTask.addEventListener('click', () => {
|
|
createTask.disabled = true;
|
|
|
|
fetch("{{ url('task/create') }}", {
|
|
method: "POST",
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Accept': 'application/json'
|
|
},
|
|
body: JSON.stringify({taskTitle})
|
|
})
|
|
.then(res => {
|
|
if (res.ok) {
|
|
window.location.reload();
|
|
} else {
|
|
createTask.textContent = 'خطا';
|
|
createTask.disabled = false;
|
|
console.error('Server error on create task action:', res.statusText);
|
|
}
|
|
})
|
|
.catch(err => {
|
|
createTask.textContent = 'خطای شبکه';
|
|
createTask.disabled = false;
|
|
console.error('Network error:', err);
|
|
});
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{{--BREAK--}}
|
|
|
|
const breakBtn = document.getElementById('breakAttendance');
|
|
let breakTimer = null;
|
|
let currentSeconds = 0;
|
|
|
|
// server-provided initial duration (string or null)
|
|
const serverDuration = {!! json_encode($duration ?? null) !!};
|
|
|
|
function parseDurationString(str) {
|
|
if (!str) return 0;
|
|
const parts = String(str).split(':').map(s => parseInt(s, 10) || 0);
|
|
if (parts.length === 3) {
|
|
return parts[0] * 3600 + parts[1] * 60 + parts[2];
|
|
} else if (parts.length === 2) {
|
|
// treat as MM:SS
|
|
return parts[0] * 60 + parts[1];
|
|
} else if (parts.length === 1) {
|
|
return parts[0];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
function formatDuration(seconds) {
|
|
const h = Math.floor(seconds / 3600);
|
|
const m = Math.floor((seconds % 3600) / 60);
|
|
const s = seconds % 60;
|
|
const mm = String(m).padStart(2, '0');
|
|
const ss = String(s).padStart(2, '0');
|
|
if (h > 0) {
|
|
return `${h}:${mm}:${ss}`;
|
|
}
|
|
return `${mm}:${ss}`;
|
|
}
|
|
|
|
function startBreakCounter(initialSeconds) {
|
|
// ensure no duplicate timer
|
|
if (breakTimer) clearInterval(breakTimer);
|
|
currentSeconds = initialSeconds || 0;
|
|
// update immediately
|
|
breakBtn.textContent = formatDuration(currentSeconds);
|
|
breakBtn.classList.add('bg-red-500');
|
|
breakBtn.classList.remove('bg-gray-500');
|
|
breakTimer = setInterval(() => {
|
|
currentSeconds++;
|
|
breakBtn.textContent = formatDuration(currentSeconds);
|
|
}, 1000);
|
|
}
|
|
|
|
function stopBreakCounter() {
|
|
if (breakTimer) {
|
|
clearInterval(breakTimer);
|
|
breakTimer = null;
|
|
}
|
|
currentSeconds = 0;
|
|
if (breakBtn) {
|
|
breakBtn.textContent = 'استراحت';
|
|
breakBtn.classList.remove('bg-red-500');
|
|
breakBtn.classList.add('bg-gray-500');
|
|
}
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
if (!breakBtn) return;
|
|
|
|
if (serverDuration !== null && serverDuration !== '') {
|
|
const secs = parseDurationString(serverDuration);
|
|
startBreakCounter(secs);
|
|
console.log(`استراحت فعال است. زمان شروع از سرور: ${serverDuration} (${secs} ثانیه).`);
|
|
} else {
|
|
stopBreakCounter();
|
|
}
|
|
});
|
|
|
|
if (breakBtn) {
|
|
breakBtn.addEventListener('click', () => {
|
|
// breakBtn.textContent = '...در حال ارسال';
|
|
// breakBtn.disabled = true;
|
|
|
|
fetch("{{ url('attendance/break') }}", {
|
|
method: "POST",
|
|
headers: {
|
|
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
|
'Accept': 'application/json'
|
|
}
|
|
})
|
|
.then(res => {
|
|
if (res.status == 'error') {
|
|
console.log(res);
|
|
window.location.reload();
|
|
} else {
|
|
console.log(res);
|
|
breakBtn.textContent = 'خطا';
|
|
breakBtn.disabled = false;
|
|
console.error('Server error on break action:', res.statusText);
|
|
window.location.reload();
|
|
}
|
|
})
|
|
.catch(err => {
|
|
console.log(err);
|
|
window.location.reload();
|
|
|
|
// breakBtn.textContent = 'خطای شبکه';
|
|
// breakBtn.disabled = false;
|
|
// console.error('Network error:', err);
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{{--let breakStarted = false;--}}
|
|
{{--let breakStartTime = null;--}}
|
|
{{--let breakTimer = null;--}}
|
|
|
|
{{--const breakBtn = document.getElementById('breakAttendance');--}}
|
|
|
|
{{--function formatLocalDatetime(date) {--}}
|
|
{{-- const year = date.getFullYear();--}}
|
|
{{-- const month = String(date.getMonth() + 1).padStart(2, '0');--}}
|
|
{{-- const day = String(date.getDate()).padStart(2, '0');--}}
|
|
{{-- const hours = String(date.getHours()).padStart(2, '0');--}}
|
|
{{-- const minutes = String(date.getMinutes()).padStart(2, '0');--}}
|
|
{{-- const seconds = String(date.getSeconds()).padStart(2, '0');--}}
|
|
|
|
{{-- return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;--}}
|
|
{{--}--}}
|
|
|
|
{{--function formatDuration(totalSeconds) {--}}
|
|
{{-- const hours = Math.floor(totalSeconds / 3600);--}}
|
|
{{-- const minutes = Math.floor((totalSeconds % 3600) / 60);--}}
|
|
|
|
{{-- const h = String(hours);--}}
|
|
{{-- const i = String(minutes).padStart(2, '0');--}}
|
|
|
|
{{-- return `${h}:${i}`;--}}
|
|
{{--}--}}
|
|
|
|
|
|
{{--breakBtn.addEventListener('click', () => {--}}
|
|
{{-- if (!breakStarted) {--}}
|
|
{{-- // شروع استراحت 🚀--}}
|
|
{{-- breakStarted = true;--}}
|
|
{{-- breakStartTime = new Date();--}}
|
|
|
|
{{-- // تغییر ظاهر دکمه و شروع تایمر (همچنان M:S نمایش داده می شود)--}}
|
|
{{-- breakBtn.classList.remove('bg-gray-500', 'hover:bg-gray-600');--}}
|
|
{{-- breakBtn.classList.add('bg-red-500', 'hover:bg-red-600');--}}
|
|
{{-- breakBtn.textContent = '00:00';--}}
|
|
|
|
{{-- let seconds = 0;--}}
|
|
{{-- breakTimer = setInterval(() => {--}}
|
|
{{-- seconds++;--}}
|
|
{{-- // اینجا همچنان به صورت دقیقه:ثانیه نمایش داده می شود--}}
|
|
{{-- const m = String(Math.floor(seconds / 60)).padStart(2, '0');--}}
|
|
{{-- const s = String(seconds % 60).padStart(2, '0');--}}
|
|
{{-- breakBtn.textContent = ` ${m}:${s}`;--}}
|
|
{{-- }, 1000);--}}
|
|
{{-- //send start time--}}
|
|
{{-- let formData = new FormData();--}}
|
|
{{-- formData.append('start_time', formatLocalDatetime(breakStartTime));--}}
|
|
|
|
{{-- formData.append('_token', '{{ csrf_token() }}');--}}
|
|
|
|
{{-- fetch("{{ url('attendance/break') }}", {--}}
|
|
{{-- method: "POST",--}}
|
|
{{-- body: formData--}}
|
|
{{-- })--}}
|
|
{{-- .then(res => res.json())--}}
|
|
{{-- .then(data => console.log('✅ Break Started Logged:', data))--}}
|
|
{{-- .catch(err => console.error('💥 Error starting break:', err));--}}
|
|
|
|
{{-- } else {--}}
|
|
{{-- // پایان استراحت 🛑--}}
|
|
{{-- breakStarted = false;--}}
|
|
{{-- const breakEndTime = new Date();--}}
|
|
{{-- clearInterval(breakTimer);--}}
|
|
|
|
{{-- // 1. محاسبه مدت زمان استراحت (بر حسب ثانیه)--}}
|
|
{{-- const durationSec = Math.floor((breakEndTime - breakStartTime) / 1000);--}}
|
|
|
|
{{-- // 2. تبدیل زمان های شروع و پایان به فرمت رشته ای--}}
|
|
{{-- const breakStartTime_str = formatLocalDatetime(breakStartTime);--}}
|
|
{{-- const breakEndTime_str = formatLocalDatetime(breakEndTime);--}}
|
|
|
|
{{-- // 3. فرمت کردن مدت زمان به H:i (فقط برای نمایش در کنسول/هشدار)--}}
|
|
{{-- const duration_formatted_h_i = formatDuration(durationSec);--}}
|
|
|
|
{{-- // 4. نمایش دکمه به حالت اولیه--}}
|
|
{{-- breakBtn.classList.remove('bg-red-500', 'hover:bg-red-600');--}}
|
|
{{-- // breakBtn.classList.add('bg-gray-500', 'hover:bg-gray-600');--}}
|
|
{{-- breakBtn.textContent = 'استراحت';--}}
|
|
|
|
{{-- // 5. ارسال دادهها به سرور--}}
|
|
{{-- let formData = new FormData();--}}
|
|
{{-- formData.append('start_time', breakStartTime_str);--}}
|
|
{{-- formData.append('end_time', breakEndTime_str);--}}
|
|
{{-- formData.append('duration_seconds', durationSec);--}}
|
|
{{-- formData.append('_token', '{{ csrf_token() }}');--}}
|
|
|
|
{{-- fetch("{{ url('attendance/break') }}", {--}}
|
|
{{-- method: "POST",--}}
|
|
{{-- body: formData--}}
|
|
{{-- })--}}
|
|
{{-- .then(res => res.json())--}}
|
|
{{-- .then(data => console.log('✅ Break saved:', data))--}}
|
|
{{-- .catch(err => console.error('💥 Error:', err));--}}
|
|
{{-- }--}}
|
|
{{--});--}}
|
|
|
|
|
|
|
|
|
|
|
|
{{-- ATTENDANCE MODAL--}}
|
|
function clearTime(fieldId) {
|
|
document.getElementById(fieldId).value = '';
|
|
}
|
|
|
|
function closeModal() {
|
|
document.getElementById('modal-container').classList.add('hidden');
|
|
}
|
|
|
|
document.getElementById('modal-container').addEventListener('click', (e) => {
|
|
if (e.target === document.getElementById('modal-container')) {
|
|
closeModal();
|
|
}
|
|
});
|
|
|
|
function confirmSubmit() {
|
|
return confirm("آیا تغییرات اعمال شوند؟");
|
|
}
|
|
|
|
function openModal(title, id, enteredAt, exitedAt) {
|
|
const isNewEntry = id === 'new';
|
|
const modalTitleElement = document.getElementById('modal-title');
|
|
|
|
const hiddenIdInput = document.getElementById('edit_id');
|
|
// const hiddenIdInput = document.getElementById('delete_id');
|
|
|
|
const deleteIdInput = document.getElementById('delete_id');
|
|
const submitButton = document.querySelector('#modal-content button[type="submit"]');
|
|
const hiddenDateInput = document.querySelector('input[name="date"]');
|
|
|
|
// مقداردهی به فرم حذف
|
|
if (deleteIdInput) {
|
|
deleteIdInput.value = id;
|
|
}
|
|
|
|
const newDateLabel = document.getElementById('new-date-label');
|
|
const newDateGroup = document.getElementById('new-date-group');
|
|
const displayDateInput = document.getElementById('display_date');
|
|
|
|
const panelLink = document.getElementById('panel-access-link');
|
|
panelLink.href = `/go_down/${id}`;
|
|
|
|
document.getElementById('modal-container').classList.remove('hidden');
|
|
|
|
const startTimeInput = document.querySelector('input[name="starttime"]');
|
|
const endTimeInput = document.querySelector('input[name="endtime"]');
|
|
|
|
// تنظیم ساعتها
|
|
if (enteredAt && !isNaN(new Date(enteredAt).getTime())) {
|
|
startTimeInput.value = new Date(enteredAt).toLocaleTimeString('en-GB', {
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
});
|
|
} else {
|
|
startTimeInput.value = '09:00';
|
|
}
|
|
|
|
if (exitedAt && !isNaN(new Date(exitedAt).getTime())) {
|
|
endTimeInput.value = new Date(exitedAt).toLocaleTimeString('en-GB', {
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
});
|
|
}
|
|
// else {
|
|
// endTimeInput.value = '17:30';
|
|
// }
|
|
|
|
|
|
if (isNewEntry) {
|
|
// حالت ثبت جدید
|
|
modalTitleElement.innerText = 'ثبت روز کاری جدید';
|
|
newDateLabel.style.display = 'block';
|
|
newDateGroup.style.display = 'block';
|
|
|
|
displayDateInput.value = '';
|
|
hiddenDateInput.value = '';
|
|
|
|
// ✅ اصلاح: مقداردهی 'new' به فیلد ID
|
|
if (hiddenIdInput) hiddenIdInput.value = 'new';
|
|
|
|
submitButton.onclick = function () {
|
|
if (hiddenDateInput.value === '') {
|
|
alert("لطفاً یک تاریخ را از تقویم انتخاب کنید.");
|
|
return false;
|
|
}
|
|
return confirmSubmit();
|
|
};
|
|
|
|
} else {
|
|
// حالت ویرایش
|
|
modalTitleElement.innerText = 'تغییر ساعت کاری';
|
|
newDateLabel.style.display = 'none';
|
|
newDateGroup.style.display = 'none';
|
|
|
|
// ✅ اصلاح: استفاده از متغیر 'id' که از جدول فرستاده شده است
|
|
if (hiddenIdInput) hiddenIdInput.value = id;
|
|
if (hiddenDateInput) hiddenDateInput.value = enteredAt;
|
|
|
|
submitButton.onclick = function () {
|
|
return confirmSubmit();
|
|
};
|
|
}
|
|
|
|
//date and clock picker
|
|
$('.clockpicker').clockpicker({
|
|
autoclose: false,
|
|
placement: 'center',
|
|
donetext: 'ثبت',
|
|
vibrate: true,
|
|
});
|
|
|
|
// --- فعالسازی تقویم ---
|
|
$(".example1").persianDatepicker({
|
|
format: "YYYY/MM/DD",
|
|
altField: '#date',
|
|
altFormat: 'YYYY-MM-DD',
|
|
calendar: {
|
|
persian: {
|
|
locale: 'fa',
|
|
leapYearMode: "astronomical"
|
|
}
|
|
},
|
|
observer: true,
|
|
initialValue: false,
|
|
initialValueType: 'gregorian',
|
|
autoClose: true,
|
|
toolbox: {
|
|
calendarSwitch: {enabled: false},
|
|
todayButton: {enabled: true, text: {fa: "امروز"}}
|
|
},
|
|
});
|
|
|
|
}
|
|
|
|
|
|
$(document).ready(function () {
|
|
|
|
// 1. فعالسازی Clockpicker
|
|
$('.clockpicker').clockpicker({
|
|
autoclose: false,
|
|
placement: 'center',
|
|
donetext: 'ثبت',
|
|
vibrate: true,
|
|
// donetext: true,
|
|
});
|
|
|
|
|
|
$(".example1").persianDatepicker({
|
|
format: "YYYY/MM/DD",
|
|
altField: '#date',
|
|
altFormat: 'YYYY-MM-DD',
|
|
calendar: {
|
|
persian: {
|
|
locale: 'fa',
|
|
leapYearMode: "astronomical"
|
|
}
|
|
},
|
|
observer: true,
|
|
initialValue: false,
|
|
initialValueType: 'gregorian',
|
|
autoClose: true,
|
|
toolbox: {
|
|
calendarSwitch: {enabled: false},
|
|
todayButton: {enabled: true, text: {fa: "امروز"}}
|
|
},
|
|
onSelect: function (unix) {
|
|
// تبدیل تاریخ انتخابی به میلادی درست با timezone ایران
|
|
const d = new persianDate(unix).toCalendar('gregorian').toLocale('en');
|
|
console.log("Gregorian (Fixed):", d.format("YYYY-MM-DD"));
|
|
}
|
|
});
|
|
|
|
// 2. فعالسازی Persian Datepicker
|
|
// $('.example1').pDatepicker({
|
|
// format: 'YYYY/MM/DD',
|
|
// // placement: 'center',
|
|
// altField: '#date', // این فیلد مخفی، تاریخ میلادی تبدیل شده را دریافت میکند
|
|
// altFormat: 'YYYY-MM-DD', // میلادی ذخیره بشه
|
|
// // changeMonth: true,
|
|
// // changeYear: true,
|
|
// // showOtherMonths: true,
|
|
// // selectOtherMonths: true,
|
|
// autoClose: true,
|
|
//
|
|
// });
|
|
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
@endsection
|