fix office location detection radius and GPS accuracy
This commit is contained in:
@@ -251,6 +251,8 @@ SVG;
|
||||
|
||||
const referenceLat = 32.6504751;
|
||||
const referenceLng = 51.6936045;
|
||||
const OFFICE_RADIUS_METERS = 100;
|
||||
const MAX_ACCURACY_CREDIT_METERS = 80;
|
||||
|
||||
const submitBtn = document.getElementById("submitBtn");
|
||||
const latInput = document.getElementById("latitude");
|
||||
@@ -278,26 +280,31 @@ SVG;
|
||||
return earthRadius * c;
|
||||
}
|
||||
|
||||
function isInsideOffice(distanceMeters, accuracyMeters) {
|
||||
const accuracyCredit = Math.min(Math.max(0, accuracyMeters || 0), MAX_ACCURACY_CREDIT_METERS);
|
||||
return Math.max(0, distanceMeters - accuracyCredit) <= OFFICE_RADIUS_METERS;
|
||||
}
|
||||
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
position => {
|
||||
const lat = position.coords.latitude;
|
||||
const lng = position.coords.longitude;
|
||||
const accuracy = position.coords.accuracy || 0;
|
||||
|
||||
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 = `مکان: خارج از شرکت`;
|
||||
}
|
||||
const inside = isInsideOffice(dist, accuracy);
|
||||
distanceMessage.textContent = inside
|
||||
? `مکان: شرکت (~${dist}م)`
|
||||
: `مکان: خارج از شرکت (~${dist}م)`;
|
||||
|
||||
distanceMessage.classList.remove("bg-gray-400", "bg-blue-500", "bg-green-500", "bg-orange-500", "cursor-not-allowed");
|
||||
if (dist < 10) {
|
||||
distanceMessage.classList.remove("bg-gray-400", "bg-blue-500", "bg-green-500", "bg-orange-500", "cursor-not-allowed", "text-green-500", "text-blue-500", "text-orange-500", "text-gray-400");
|
||||
if (inside) {
|
||||
distanceMessage.classList.add("text-green-500");
|
||||
} else if (dist < 50) {
|
||||
} else if (dist < OFFICE_RADIUS_METERS * 2) {
|
||||
distanceMessage.classList.add("text-blue-500");
|
||||
} else if (dist > 2000) {
|
||||
distanceMessage.classList.add("text-orange-500");
|
||||
@@ -311,7 +318,7 @@ SVG;
|
||||
},
|
||||
error => alert("⛔ خطا در دریافت موقعیت مکانی: " + error.message), {
|
||||
enableHighAccuracy: true,
|
||||
timeout: 10000,
|
||||
timeout: 20000,
|
||||
maximumAge: 0
|
||||
}
|
||||
);
|
||||
|
||||
@@ -311,12 +311,12 @@ if (!empty($user->tasks)) {
|
||||
</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')) : '' }};">
|
||||
<td style="border-right: 1px solid #ddd; padding: 4px; background-color: {{$item->entered_at && $item->distance ? ($item->requested !== null ? '#fad1d1' :($item->distance < 100 ? '#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')) : '' }};">
|
||||
<td style="border-right: 1px solid #ddd; padding: 4px; background-color: {{$item->exited_at && $item->distance_exit ? ($item->requested !== null ? '#fad1d1' :($item->distance_exit < 100 ? '#d1fae5' : '#edae80')) : '' }};">
|
||||
{{ $item->exited_at ? \Carbon\Carbon::parse($item->exited_at)->format('H:i') : '-' }}
|
||||
</td>
|
||||
|
||||
@@ -646,8 +646,12 @@ if (!empty($user->tasks)) {
|
||||
const distanceMessage = document.getElementById("distanceMessage");
|
||||
|
||||
|
||||
// مختصات دفتر / شرکت
|
||||
const referenceLat = 32.6504751;
|
||||
const referenceLng = 51.6936045;
|
||||
// شعاع مجاز (متر) — GPS داخل ساختمان معمولاً ۲۰–۸۰ متر خطا دارد
|
||||
const OFFICE_RADIUS_METERS = 100;
|
||||
const MAX_ACCURACY_CREDIT_METERS = 80;
|
||||
|
||||
const submitBtn = document.getElementById("submitBtn");
|
||||
const latInput = document.getElementById("latitude");
|
||||
@@ -677,57 +681,136 @@ if (!empty($user->tasks)) {
|
||||
return earthRadius * c;
|
||||
}
|
||||
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
position => {
|
||||
const lat = position.coords.latitude;
|
||||
const lng = position.coords.longitude;
|
||||
function isInsideOffice(distanceMeters, accuracyMeters) {
|
||||
const accuracyCredit = Math.min(Math.max(0, accuracyMeters || 0), MAX_ACCURACY_CREDIT_METERS);
|
||||
const effectiveDistance = Math.max(0, distanceMeters - accuracyCredit);
|
||||
return effectiveDistance <= OFFICE_RADIUS_METERS;
|
||||
}
|
||||
|
||||
latInput.value = lat;
|
||||
lngInput.value = lng;
|
||||
function applyLocationResult(lat, lng, accuracyMeters) {
|
||||
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 = `مکان: خارج از شرکت`;
|
||||
}
|
||||
const dist = Math.round(getDistanceInMeters(referenceLat, referenceLng, lat, lng));
|
||||
distanceInput.value = dist;
|
||||
const inside = isInsideOffice(dist, accuracyMeters);
|
||||
const accuracyText = accuracyMeters
|
||||
? ` · دقت ±${Math.round(accuracyMeters)}م`
|
||||
: '';
|
||||
|
||||
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");
|
||||
distanceMessage.textContent = inside
|
||||
? `مکان: شرکت (~${dist}م)${accuracyText}`
|
||||
: `مکان: خارج از شرکت (~${dist}م)${accuracyText}`;
|
||||
|
||||
},
|
||||
error => {
|
||||
const lat = 32.6520532791536; // از مختصات ثابت استفاده کنید
|
||||
const lng = 51.68472614422439; // از مختصات ثابت استفاده کنید
|
||||
distanceMessage.classList.remove(
|
||||
"bg-gray-400", "bg-blue-500", "bg-green-500", "bg-orange-500",
|
||||
"cursor-not-allowed", "text-green-500", "text-blue-500",
|
||||
"text-orange-500", "text-gray-400"
|
||||
);
|
||||
if (inside) {
|
||||
distanceMessage.classList.add("text-green-500");
|
||||
} else if (dist <= OFFICE_RADIUS_METERS * 2) {
|
||||
distanceMessage.classList.add("text-blue-500");
|
||||
} else if (dist > 2000) {
|
||||
distanceMessage.classList.add("text-orange-500");
|
||||
} else {
|
||||
distanceMessage.classList.add("text-gray-400");
|
||||
}
|
||||
|
||||
const dist = Math.round(getDistanceInMeters(referenceLat, referenceLng, lat, lng));
|
||||
distanceInput.value = dist;
|
||||
distanceMessage.textContent = `مکان: خارج از شرکت`;
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.classList.remove("bg-gray-400", "cursor-not-allowed");
|
||||
submitBtn.classList.add("bg-cyan-500", "hover:bg-cyan-700", "cursor-pointer");
|
||||
}
|
||||
|
||||
distanceMessage.classList.remove("bg-gray-400", "bg-blue-500", "bg-green-500", "bg-orange-500", "cursor-not-allowed");
|
||||
function locateUser() {
|
||||
if (!navigator.geolocation) {
|
||||
distanceMessage.textContent = 'موقعیتیاب در دسترس نیست';
|
||||
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
|
||||
return;
|
||||
}
|
||||
);
|
||||
|
||||
distanceMessage.textContent = 'در حال بررسی موقعیت...';
|
||||
distanceMessage.classList.remove("text-green-500", "text-blue-500", "text-orange-500", "text-gray-400");
|
||||
|
||||
const geoOptions = {
|
||||
enableHighAccuracy: true,
|
||||
timeout: 20000,
|
||||
maximumAge: 0,
|
||||
};
|
||||
|
||||
let bestReading = null;
|
||||
let watchId = null;
|
||||
let finished = false;
|
||||
|
||||
const finishWithBest = () => {
|
||||
if (finished) return;
|
||||
finished = true;
|
||||
if (watchId !== null) {
|
||||
navigator.geolocation.clearWatch(watchId);
|
||||
}
|
||||
if (bestReading) {
|
||||
applyLocationResult(
|
||||
bestReading.lat,
|
||||
bestReading.lng,
|
||||
bestReading.accuracy
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const considerReading = (position) => {
|
||||
const lat = position.coords.latitude;
|
||||
const lng = position.coords.longitude;
|
||||
const accuracy = position.coords.accuracy || 9999;
|
||||
const dist = getDistanceInMeters(referenceLat, referenceLng, lat, lng);
|
||||
const score = dist + Math.min(accuracy, 150);
|
||||
|
||||
if (!bestReading || score < bestReading.score) {
|
||||
bestReading = { lat, lng, accuracy, dist, score };
|
||||
}
|
||||
|
||||
// اگر با دقت خوب داخل محدوده شدیم، زودتر تمام کن
|
||||
if (isInsideOffice(dist, accuracy) && accuracy <= 60) {
|
||||
finishWithBest();
|
||||
}
|
||||
};
|
||||
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(position) => {
|
||||
considerReading(position);
|
||||
// چند ثانیه watch برای خواندن دقیقتر داخل ساختمان
|
||||
watchId = navigator.geolocation.watchPosition(
|
||||
considerReading,
|
||||
() => finishWithBest(),
|
||||
geoOptions
|
||||
);
|
||||
setTimeout(finishWithBest, 5000);
|
||||
},
|
||||
() => {
|
||||
// تلاش دوم بدون الزام دقت بالا
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
(position) => {
|
||||
considerReading(position);
|
||||
finishWithBest();
|
||||
},
|
||||
() => {
|
||||
distanceMessage.textContent = 'موقعیت دریافت نشد — میتوانید ورود بزنید';
|
||||
distanceMessage.classList.add("text-orange-500");
|
||||
distanceInput.value = '';
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.classList.remove("bg-gray-400", "cursor-not-allowed");
|
||||
submitBtn.classList.add("bg-cyan-500", "hover:bg-cyan-700", "cursor-pointer");
|
||||
},
|
||||
{ enableHighAccuracy: false, timeout: 10000, maximumAge: 60000 }
|
||||
);
|
||||
},
|
||||
geoOptions
|
||||
);
|
||||
}
|
||||
|
||||
locateUser();
|
||||
const attendanceForm = document.getElementById('attendanceForm');
|
||||
|
||||
const output = document.getElementById('output');
|
||||
|
||||
Reference in New Issue
Block a user