308 lines
10 KiB
JavaScript
308 lines
10 KiB
JavaScript
// Configure pdf.js worker
|
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
|
|
|
|
const canvas = document.getElementById('signatureCanvas');
|
|
const ctx = canvas.getContext('2d');
|
|
let isDrawing = false;
|
|
let hasSignature = false;
|
|
let ws = null;
|
|
let currentPdf = null;
|
|
let pdfDoc = null;
|
|
let currentPageNum = 1;
|
|
let totalPages = 1;
|
|
|
|
connectWebSocket();
|
|
|
|
function connectWebSocket() {
|
|
// Use current host (works for localhost, IP addresses, and reverse proxy)
|
|
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
const wsHost = window.location.hostname;
|
|
// If using HTTPS (reverse proxy), use same port as page (usually 443, no port needed)
|
|
// If using HTTP directly, use port 8080
|
|
const wsPort = window.location.protocol === 'https:' ? '' : ':8080';
|
|
const wsUrl = `${wsProtocol}//${wsHost}${wsPort}`;
|
|
console.log('Verbinde WebSocket zu:', wsUrl);
|
|
ws = new WebSocket(wsUrl);
|
|
|
|
ws.onopen = () => {
|
|
console.log('WebSocket verbunden');
|
|
document.getElementById('loadingSection').style.display = 'none';
|
|
document.getElementById('waitingSection').style.display = 'block';
|
|
|
|
// Register as signature station
|
|
ws.send(JSON.stringify({
|
|
type: 'register_signature'
|
|
}));
|
|
};
|
|
|
|
ws.onmessage = async (event) => {
|
|
const data = JSON.parse(event.data);
|
|
|
|
if (data.type === 'already_connected') {
|
|
console.log('⚠️ Bereits eine andere Signatur-Station verbunden');
|
|
// Show warning message
|
|
const warning = document.getElementById('alreadyConnectedWarning');
|
|
if (warning) {
|
|
warning.style.display = 'block';
|
|
}
|
|
} else if (data.type === 'pdf') {
|
|
console.log('PDF empfangen');
|
|
currentPdf = new Uint8Array(data.pdf);
|
|
|
|
// Show PDF notification
|
|
document.getElementById('waitingSection').style.display = 'none';
|
|
document.getElementById('signatureSection').style.display = 'block';
|
|
document.getElementById('pdfDisplay').classList.add('show');
|
|
|
|
// Render ALL pages of PDF
|
|
await renderPdfPreview(currentPdf);
|
|
|
|
// Clear previous signature if any
|
|
clearSignature();
|
|
} else if (data.type === 'page_change') {
|
|
currentPageNum = data.pageNum;
|
|
totalPages = data.totalPages;
|
|
|
|
// Scroll to the specific page
|
|
const pageCanvas = document.getElementById(`page-canvas-${data.pageNum}`);
|
|
if (pageCanvas) {
|
|
pageCanvas.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
}
|
|
} else if (data.type === 'signature_placed') {
|
|
console.log('✅ Unterschrift wurde platziert! Reset in 5 Sekunden...');
|
|
console.log('Empfangene Daten:', JSON.stringify(data));
|
|
|
|
// Show immediate feedback
|
|
const successMsg = document.getElementById('successMessage');
|
|
successMsg.classList.add('show');
|
|
|
|
// Reset after 5 seconds
|
|
setTimeout(() => {
|
|
console.log('Auto-Reset wird durchgeführt...');
|
|
|
|
// Clear signature
|
|
clearSignature();
|
|
|
|
// Hide success message
|
|
document.getElementById('successMessage').classList.remove('show');
|
|
|
|
// Hide PDF and signature section, show waiting
|
|
document.getElementById('signatureSection').style.display = 'none';
|
|
document.getElementById('pdfDisplay').classList.remove('show');
|
|
document.getElementById('waitingSection').style.display = 'block';
|
|
|
|
// Reset PDF data
|
|
currentPdf = null;
|
|
pdfDoc = null;
|
|
currentPageNum = 1;
|
|
totalPages = 1;
|
|
|
|
console.log('Bereit für nächste Unterschrift');
|
|
}, 5000);
|
|
} else if (data.type === 'discard') {
|
|
console.log('🔄 Verwerfen-Nachricht empfangen, setze zurück...');
|
|
resetSignatureStation();
|
|
}
|
|
};
|
|
|
|
ws.onerror = (error) => {
|
|
console.error('WebSocket Fehler:', error);
|
|
document.getElementById('loadingSection').innerHTML =
|
|
'<p style="color: #dc3545;">❌ Verbindung zum Server fehlgeschlagen.</p>';
|
|
};
|
|
|
|
ws.onclose = () => {
|
|
console.log('WebSocket getrennt');
|
|
setTimeout(connectWebSocket, 1000);
|
|
};
|
|
}
|
|
|
|
async function renderPdfPreview(pdfBytes, pageNum = null) {
|
|
try {
|
|
// Create fresh copy to prevent detachment
|
|
const safeCopy = new Uint8Array(pdfBytes.buffer.slice(0));
|
|
|
|
console.log('renderPdfPreview aufgerufen mit', pdfBytes.length, 'bytes');
|
|
const loadingTask = pdfjsLib.getDocument({ data: safeCopy });
|
|
pdfDoc = await loadingTask.promise;
|
|
totalPages = pdfDoc.numPages;
|
|
|
|
// Update page info
|
|
document.getElementById('pageInfoSignature').textContent = `${totalPages} Seite${totalPages > 1 ? 'n' : ''}`;
|
|
|
|
// Get container
|
|
const container = document.getElementById('pdfPagesContainer');
|
|
container.innerHTML = ''; // Clear existing content
|
|
|
|
// Render all pages
|
|
for (let pageNum = 1; pageNum <= totalPages; pageNum++) {
|
|
|
|
// Add page separator if not first page
|
|
if (pageNum > 1) {
|
|
const separator = document.createElement('div');
|
|
separator.className = 'page-separator';
|
|
separator.textContent = `Seite ${pageNum}`;
|
|
container.appendChild(separator);
|
|
} else {
|
|
// First page indicator
|
|
const separator = document.createElement('div');
|
|
separator.className = 'page-separator';
|
|
separator.textContent = `Seite 1`;
|
|
container.appendChild(separator);
|
|
}
|
|
|
|
// Create canvas for this page
|
|
const canvas = document.createElement('canvas');
|
|
canvas.className = 'pdf-preview-canvas';
|
|
canvas.id = `page-canvas-${pageNum}`;
|
|
container.appendChild(canvas);
|
|
|
|
// Render page
|
|
const page = await pdfDoc.getPage(pageNum);
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
const viewport = page.getViewport({ scale: 1.2 });
|
|
canvas.width = viewport.width;
|
|
canvas.height = viewport.height;
|
|
|
|
const renderContext = {
|
|
canvasContext: ctx,
|
|
viewport: viewport
|
|
};
|
|
|
|
await page.render(renderContext).promise;
|
|
}
|
|
|
|
console.log('Alle', totalPages, 'Seiten erfolgreich gerendert');
|
|
} catch (error) {
|
|
console.error('Fehler beim Rendern der PDF Vorschau:', error);
|
|
}
|
|
}
|
|
|
|
// Canvas setup
|
|
ctx.strokeStyle = '#000';
|
|
ctx.lineWidth = 2;
|
|
ctx.lineCap = 'round';
|
|
ctx.lineJoin = 'round';
|
|
|
|
function startDrawing(e) {
|
|
isDrawing = true;
|
|
const pos = getPosition(e);
|
|
ctx.beginPath();
|
|
ctx.moveTo(pos.x, pos.y);
|
|
}
|
|
|
|
function draw(e) {
|
|
if (!isDrawing) return;
|
|
e.preventDefault();
|
|
|
|
const pos = getPosition(e);
|
|
ctx.lineTo(pos.x, pos.y);
|
|
ctx.stroke();
|
|
|
|
hasSignature = true;
|
|
document.getElementById('submitButton').disabled = false;
|
|
}
|
|
|
|
function stopDrawing() {
|
|
isDrawing = false;
|
|
}
|
|
|
|
function getPosition(e) {
|
|
const rect = canvas.getBoundingClientRect();
|
|
const scaleX = canvas.width / rect.width;
|
|
const scaleY = canvas.height / rect.height;
|
|
|
|
if (e.touches && e.touches.length > 0) {
|
|
return {
|
|
x: (e.touches[0].clientX - rect.left) * scaleX,
|
|
y: (e.touches[0].clientY - rect.top) * scaleY
|
|
};
|
|
}
|
|
|
|
return {
|
|
x: (e.clientX - rect.left) * scaleX,
|
|
y: (e.clientY - rect.top) * scaleY
|
|
};
|
|
}
|
|
|
|
// Mouse events
|
|
canvas.addEventListener('mousedown', startDrawing);
|
|
canvas.addEventListener('mousemove', draw);
|
|
canvas.addEventListener('mouseup', stopDrawing);
|
|
canvas.addEventListener('mouseout', stopDrawing);
|
|
|
|
// Touch events
|
|
canvas.addEventListener('touchstart', startDrawing);
|
|
canvas.addEventListener('touchmove', draw);
|
|
canvas.addEventListener('touchend', stopDrawing);
|
|
|
|
// Clear button
|
|
document.getElementById('clearButton').addEventListener('click', () => {
|
|
clearSignature();
|
|
});
|
|
|
|
function clearSignature() {
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
hasSignature = false;
|
|
document.getElementById('submitButton').disabled = true;
|
|
document.getElementById('successMessage').classList.remove('show');
|
|
document.getElementById('errorMessage').classList.remove('show');
|
|
}
|
|
|
|
function resetSignatureStation() {
|
|
console.log('=== SIGNATUR-STATION ZURÜCKSETZEN ===');
|
|
|
|
// Clear signature canvas
|
|
clearSignature();
|
|
|
|
// Hide success and error messages
|
|
document.getElementById('successMessage').classList.remove('show');
|
|
document.getElementById('errorMessage').classList.remove('show');
|
|
|
|
// Hide PDF and signature section, show waiting
|
|
document.getElementById('signatureSection').style.display = 'none';
|
|
document.getElementById('pdfDisplay').classList.remove('show');
|
|
document.getElementById('waitingSection').style.display = 'block';
|
|
|
|
// Clear PDF pages container
|
|
const container = document.getElementById('pdfPagesContainer');
|
|
if (container) {
|
|
container.innerHTML = '';
|
|
}
|
|
|
|
// Reset PDF data
|
|
currentPdf = null;
|
|
pdfDoc = null;
|
|
currentPageNum = 1;
|
|
totalPages = 1;
|
|
|
|
console.log('Signatur-Station zurückgesetzt - bereit für neue PDF');
|
|
}
|
|
|
|
// Submit button
|
|
document.getElementById('submitButton').addEventListener('click', async () => {
|
|
if (!hasSignature || !ws || ws.readyState !== WebSocket.OPEN) return;
|
|
|
|
try {
|
|
// Get signature as data URL
|
|
const signatureDataUrl = canvas.toDataURL('image/png');
|
|
|
|
// Send to server (no session ID needed)
|
|
ws.send(JSON.stringify({
|
|
type: 'signature',
|
|
signature: signatureDataUrl
|
|
}));
|
|
|
|
// Show success message
|
|
document.getElementById('successMessage').classList.add('show');
|
|
document.getElementById('submitButton').disabled = true;
|
|
|
|
console.log('Unterschrift gesendet, warte auf Platzierungs-Bestätigung...');
|
|
|
|
} catch (error) {
|
|
console.error('Fehler beim Senden:', error);
|
|
document.getElementById('errorMessage').classList.add('show');
|
|
}
|
|
});
|