خطأ: مجلد vendor غير موجود على الاستضافة. يرجى التأكد من رفع مجلد المكتبات (vendor) مع باقي ملفات النظام، أو تنفيذ أمر composer install إذا كنت تستخدم سطر الأوامر.
"; require_once 'includes/footer.php'; exit; } require $autoloadPath; use Rats\Zkteco\Lib\ZKTeco; if (!isAdmin()) { echo "
ليس لديك صلاحية للوصول إلى هذه الصفحة.
"; require_once 'includes/footer.php'; exit; } $error = ''; $success = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_POST['save_settings'])) { $ip = trim($_POST['ip_address']); $port = (int)$_POST['port']; if ($ip && $port) { $stmt = db()->prepare("UPDATE hr_zkteco_settings SET ip_address = ?, port = ? WHERE id = 1"); $stmt->execute([$ip, $port]); $success = "تم حفظ الإعدادات بنجاح."; } else { $error = "يرجى تعبئة الحقول المطلوبة."; } } $stmt = db()->query("SELECT * FROM hr_zkteco_settings LIMIT 1"); $settings = $stmt->fetch(); $ip = $settings['ip_address'] ?? '192.168.1.201'; $port = $settings['port'] ?? 4370; if (isset($_POST['test_connection'])) { try { $zk = new ZKTeco($ip, $port); if ($zk->connect()) { $success = "تم الاتصال بالجهاز بنجاح (الإصدار: " . htmlspecialchars($zk->version() ?? 'غير معروف') . ")"; $zk->disconnect(); } else { $error = "فشل الاتصال بالجهاز. يرجى التأكد من أن الجهاز على نفس الشبكة والمنفذ مفتوح (عادة 4370)."; } } catch (Exception $e) { $error = "خطأ أثناء الاتصال: " . $e->getMessage(); } } if (isset($_POST['sync_logs'])) { try { $zk = new ZKTeco($ip, $port); if ($zk->connect()) { $attendance = $zk->getAttendance(); $empStmt = db()->query("SELECT id, zkteco_uid FROM hr_employees WHERE zkteco_uid IS NOT NULL AND zkteco_uid != '' AND status = 'active'"); $empMap = []; while ($emp = $empStmt->fetch()) { $empMap[(string)$emp['zkteco_uid']] = $emp['id']; } $syncedCount = 0; if (is_array($attendance)) { $attData = []; foreach ($attendance as $att) { $uid = (string)$att['id']; if (isset($empMap[$uid])) { $emp_id = $empMap[$uid]; $timeStr = $att['timestamp']; $date = date('Y-m-d', strtotime($timeStr)); $time = date('H:i:s', strtotime($timeStr)); if (!isset($attData[$emp_id][$date])) { $attData[$emp_id][$date] = ['min' => $time, 'max' => $time]; } else { if ($time < $attData[$emp_id][$date]['min']) $attData[$emp_id][$date]['min'] = $time; if ($time > $attData[$emp_id][$date]['max']) $attData[$emp_id][$date]['max'] = $time; } } } foreach ($attData as $emp_id => $dates) { foreach ($dates as $date => $times) { $check_in = $times['min']; $check_out = ($times['max'] != $times['min']) ? $times['max'] : null; $chkStmt = db()->prepare("SELECT id, check_in, check_out FROM hr_attendance WHERE employee_id = ? AND date = ?"); $chkStmt->execute([$emp_id, $date]); $existing = $chkStmt->fetch(); if ($existing) { $upd_in = $existing['check_in']; $upd_out = $existing['check_out']; $changed = false; if (empty($upd_in) || $check_in < $upd_in) { $upd_in = $check_in; $changed = true; } if ($check_out && (empty($upd_out) || $check_out > $upd_out)) { $upd_out = $check_out; $changed = true; } if ($changed) { $uStmt = db()->prepare("UPDATE hr_attendance SET check_in = ?, check_out = ?, status = 'present' WHERE id = ?"); $uStmt->execute([$upd_in, $upd_out, $existing['id']]); $syncedCount++; } } else { $iStmt = db()->prepare("INSERT INTO hr_attendance (employee_id, date, check_in, check_out, status) VALUES (?, ?, ?, ?, 'present')"); $iStmt->execute([$emp_id, $date, $check_in, $check_out]); $syncedCount++; } } } } $zk->disconnect(); if ($syncedCount > 0) { $success = "تم مزامنة $syncedCount سجل حضور (تحديث / إنشاء) بنجاح."; } else { $success = "تم الاتصال بنجاح ولكن لم يتم العثور على سجلات جديدة للموظفين المعرفين."; } } else { $error = "فشل الاتصال بالجهاز."; } } catch (Exception $e) { $error = "حدث خطأ أثناء المزامنة: " . $e->getMessage(); } } } else { $stmt = db()->query("SELECT * FROM hr_zkteco_settings LIMIT 1"); $settings = $stmt->fetch(); $ip = $settings['ip_address'] ?? '192.168.1.201'; $port = $settings['port'] ?? 4370; } ?>

ربط جهاز البصمة ZKTeco

اختر طريقة الربط المناسبة للشبكة الخاصة بك لسحب سجلات الحضور.

هذه الطريقة تتطلب أن يكون الخادم (السيرفر) قادراً على الوصول إلى عنوان IP الخاص بالجهاز. إذا كان الجهاز في شبكة محلية مختلفة ولا يوجد IP ثابت، استخدم الطريقة 2.
إعدادات الاتصال المباشر
العمليات

اختبر الاتصال أو ابدأ بسحب البيانات الان.

النظام جاهز لاستقبال البصمات تلقائياً (ADMS/WDMS)

من خلال هذه الطريقة، يقوم جهاز البصمة بإرسال سجلات الحضور تلقائياً إلى هذا النظام عبر الإنترنت. هذه الطريقة مثالية إذا كان جهاز البصمة في شبكة محلية بدون IP ثابت (Public IP).

خطوات الإعداد على جهاز البصمة ZKTeco:
  • 1. إعدادات الشبكة (Comm.)
    افتح القائمة الرئيسية للجهاز واذهب إلى COMM. ثم Cloud Server Setting أو ADMS.
  • 2. عنوان السيرفر (Server Address)
    أدخل عنوان هذا النظام أو الـ IP الخاص به.
    مثال: إذا كان عنوان التطبيق http://your-app.com أدخل فقط your-app.com
  • 3. منفذ السيرفر (Server Port)
    أدخل المنفذ: 80 للاتصال العادي (أو 443 إذا كنت تستخدم HTTPS مدعوم).
  • 4. تفعيل المزامنة
    بمجرد الحفظ، سيبدأ الجهاز بإرسال بيانات الحضور تلقائياً إلى السيرفر. ستظهر السجلات في صفحة "سجل الحضور".
خطوة هامة لربط الموظفين

لكي يتم احتساب البصمات للموظف الصحيح، تأكد من الذهاب إلى قائمة الموظفين وتعديل بيانات كل موظف وإضافة ZKTeco UID (رقم الموظف في جهاز البصمة).