Skip to main content

Οδηγός Υλοποίησης μέσω Browser

Μπορείς να φτιάξεις ένα πλήρες σύστημα σάρωσης Κάρτας Εργασίας χρησιμοποιώντας μόνο έναν web browser — χωρίς native εφαρμογή για iOS ή Android. Αυτή η σελίδα καλύπτει και τις δύο προσεγγίσεις (QR code και NFC κάρτα), την κλήση του Ergani API και τη διαχείριση του ορίου των 15 λεπτών όταν η σύνδεση διακοπεί.

Χωρίς app store

Το camera API του browser και το Web NFC API είναι διαθέσιμα σε σύγχρονους browsers. Μία απλή web εφαρμογή αναπτυγμένη στον server σου αρκεί για να τρέξεις ένα επαγγελματικό σύστημα σάρωσης σε tablet στην είσοδο.

Πώς λειτουργεί

Δύο πλευρές:

  • Εργαζόμενος — δείχνει τον QR κώδικά του από το κινητό, ή αγγίζει μια φυσική NFC κάρτα στον αναγνώστη.
  • Tablet εργοδότη — διαβάζει το QR/NFC, εντοπίζει το ΑΦΜ του εργαζόμενου και αποστέλλει το γεγονός άφιξης ή αποχώρησης στο Ergani API εντός 15 λεπτών.
Κινητό εργαζόμενου Tablet εργοδότη Ο server σου Ergani API
─────────────────── ──────────────────────── ───────────── ──────────
Δείχνει QR/NFC → Διαβάζει κάρτα ή QR → POST /workcard → WRKCardSE
Βρίσκει ΑΦΜ εργαζόμενου Ώρα Ελλάδας Επιστρέφει OK
Εμφανίζει ✅ στην οθόνη Διαχειρίζεται JWT

Προσέγγιση QR Code

Λειτουργεί σε οποιαδήποτε συσκευή — iPhone, Android, desktop.

Πλευρά εργαζόμενου — εμφάνιση QR

Δημιούργησε QR code από το ΑΦΜ του εργαζόμενου και εμφάνισέ το στον browser του.

npm install qrcode
import QRCode from 'qrcode'

async function showWorkerQR(afm) {
const canvas = document.getElementById('qr-canvas')
await QRCode.toCanvas(canvas, afm, { width: 300 })
}

Ο εργαζόμενος ανοίγει αυτή τη σελίδα στο κινητό του και το κρατά μπροστά στον αναγνώστη.

Πλευρά εργοδότη — σάρωση με κάμερα

npm install html5-qrcode
import { Html5QrcodeScanner } from 'html5-qrcode'

const scanner = new Html5QrcodeScanner('reader', { fps: 10, qrbox: 250 })

scanner.render((afm) => {
// afm είναι το ΑΦΜ του εργαζόμενου που διαβάστηκε από το QR
handleScan(afm)
})

Προσέγγιση NFC κάρτας

Οι εργαζόμενοι παίρνουν μια φθηνή NFC κάρτα (€0,20–0,50 η κάθε μία). Την αγγίζουν στο Android tablet του εργοδότη — δεν χρειάζεται κινητό.

Μόνο Android + Chrome

Το Web NFC API (NDEFReader) λειτουργεί μόνο στο Chrome σε Android. Δεν υποστηρίζεται στο iOS — χρησιμοποίησε QR ως fallback για χρήστες iPhone.

async function startNFCScanner() {
if (!('NDEFReader' in window)) {
showError('Το NFC δεν υποστηρίζεται — χρησιμοποίησε QR code')
return
}

const reader = new NDEFReader()
await reader.scan() // ζητά άδεια NFC

reader.addEventListener('reading', ({ serialNumber }) => {
// serialNumber είναι το μοναδικό ID της κάρτας
// π.χ. "04:A3:2F:11:BC:44:80"
handleScan(serialNumber)
})
}

Αποθηκεύεις μια αντιστοίχιση cardId → ΑΦΜ εργαζόμενου στη βάση δεδομένων σου. Όταν αγγίξει κάρτα, βρίσκεις τον εργαζόμενο και προχωράς.

QR vs NFC

QR CodeNFC κάρτα
Λειτουργεί σε iPhone
ΤαχύτηταΠιο αργό (σκόπευση κάμερας)Πιο γρήγορο (απλώς άγγιξε)
Κόστος κάρταςΔωρεάν (ο εργαζόμενος χρησιμοποιεί κινητό)€0,20–0,50 ανά κάρτα
Συσκευή εργοδότηΟποιοδήποτε κινητό ή tabletΜόνο Android
Επαγγελματική εμφάνισηΕντάξει✅ Ναι

Σύσταση: υποστήριξε και τις δύο. Εργαζόμενοι χωρίς smartphone χρησιμοποιούν NFC κάρτα. Η κλήση του Ergani API είναι ίδια και στις δύο περιπτώσεις.

Κλήση του Ergani API

Μόλις έχεις το ΑΦΜ του εργαζόμενου, στείλε το γεγονός από τον server σου. Μην καλείς το Ergani API απευθείας από τον browser — κράτα το JWT token server-side.

// Browser → ο server σου
async function handleScan(employeeId) {
const employee = await getEmployeeByCardId(employeeId) // αναζήτηση στη βάση σου
if (!employee) { showError('Άγνωστη κάρτα'); return }

const eventType = getNextEventType(employee) // 'arrival' ή 'departure'

await fetch('/api/workcard', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
afm: employee.afm,
branchId: currentBranch.id,
type: eventType,
timestamp: new Date().toISOString()
})
})

showSuccess(`${employee.name}${eventType}`)
}
// Ο server σου → Ergani API
app.post('/api/workcard', async (req, res) => {
const { afm, branchId, type, timestamp } = req.body

const payload = {
f_afm_ergodoti: employer.afm,
f_aa_pararthmatos: branchId,
f_afm_ergazomenos: afm,
f_date: toGreekLocalTime(timestamp), // ⚠️ δες σημείωση παρακάτω
f_type: type === 'arrival' ? '0' : '1'
}

const response = await fetch(
'https://eservices.yeka.gr/WebservicesAPI/Api/Documents/WRKCardSE',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${erganiToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
}
)

res.json(await response.json())
})
Ώρα Ελλάδας — όχι UTC

Το f_date πρέπει να είναι σε τοπική ώρα Ελλάδας (UTC+2 χειμώνα, UTC+3 καλοκαίρι με θερινή ώρα). Η αποστολή σε UTC κάνει τις υποβολές να φαίνονται εκπρόθεσμες και απορρίπτονται. Μετατροπή πριν την αποστολή:

function toGreekLocalTime(isoString) {
return new Date(isoString).toLocaleString('sv-SE', {
timeZone: 'Europe/Athens'
}).replace(' ', 'T')
}

Offline ουρά — διαχείριση του ορίου 15 λεπτών

Αν η σύνδεση διακοπεί κατά τη διάρκεια της βάρδιας, αποθήκευσε τις σαρώσεις τοπικά και δοκίμασε ξανά όταν επιστρέψει η σύνδεση.

async function submitWithFallback(payload) {
try {
await callErganiAPI(payload)
} catch {
const queue = JSON.parse(localStorage.getItem('wc_queue') || '[]')
queue.push({ payload, queuedAt: Date.now() })
localStorage.setItem('wc_queue', JSON.stringify(queue))
showWarning('Αποθηκεύτηκε offline — θα σταλεί όταν επιστρέψει σύνδεση')
}
}

async function flushQueue() {
const queue = JSON.parse(localStorage.getItem('wc_queue') || '[]')
if (!queue.length) return

const now = Date.now()
for (const item of queue) {
const ageMinutes = (now - item.queuedAt) / 60000
if (ageMinutes > 15) {
// Σήμανση ως εκπρόθεσμη — το Ergani απαιτεί αιτιολόγηση
item.payload.late = true
item.payload.lateReason = 'EMPLOYER_SYSTEM_FAILURE'
}
await callErganiAPI(item.payload)
}

localStorage.removeItem('wc_queue')
}

window.addEventListener('online', flushQueue)
Αιτιολόγηση εκπρόθεσμης υποβολής

Αν έχουν περάσει περισσότερα από 15 λεπτά, η υποβολή θεωρείται εκπρόθεσμη. Αποδεκτοί κωδικοί αιτιολόγησης: EMPLOYER_SYSTEM_FAILURE, POWER_TELECOM_OUTAGE, ERGANI_CONNECTIVITY. Οφείλεις επίσης να ειδοποιήσεις αμέσως την Επιθεώρηση Εργασίας κατά την έναρξη και τη λήξη της βλάβης. Βλ. Επισκόπηση Κάρτας Εργασίας.

Επόμενα βήματα