feat: téléversement mobile par QR code — alternative AirDrop pour clients en magasin
Page publique /upload.php (mobile-first, sans auth) : le client scanne un QR code au comptoir, choisit le poste de destination, et envoie ses documents. Les fichiers sont déposés dans le share SMB du compte, enregistrés en BDD (mêmes tables que les mails) et déclenchent le webhook si configuré. Page admin /admin/qrcode.php pour générer/imprimer les QR codes par poste. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017SChGCatJdbmZKCyYvTJMf
This commit is contained in:
@@ -123,6 +123,12 @@ html_navbar('accounts');
|
||||
<div class="container-fluid">
|
||||
<?php flash_render(); ?>
|
||||
|
||||
<div class="d-flex justify-content-end mb-3">
|
||||
<a href="/admin/qrcode.php" class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-qr-code me-1"></i>QR Codes téléversement
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
|
||||
<!-- Formulaire création -->
|
||||
|
||||
106
web/admin/qrcode.php
Normal file
106
web/admin/qrcode.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../includes/db.php';
|
||||
require_once __DIR__ . '/../includes/auth.php';
|
||||
require_once __DIR__ . '/../includes/layout.php';
|
||||
|
||||
admin_check();
|
||||
|
||||
$accounts = db()->query('SELECT id, username, display_name FROM accounts WHERE active = 1 ORDER BY username')->fetchAll();
|
||||
|
||||
html_head('QR Codes Upload');
|
||||
html_navbar('accounts');
|
||||
?>
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h5 class="mb-0"><i class="bi bi-qr-code me-2"></i>QR Codes — Téléversement mobile</h5>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="/admin/accounts.php" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-arrow-left me-1"></i>Comptes
|
||||
</a>
|
||||
<button class="btn btn-outline-primary btn-sm" onclick="window.print()">
|
||||
<i class="bi bi-printer me-1"></i>Imprimer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info small">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
Imprimez et affichez ces QR codes au comptoir. Le client scanne avec son téléphone et envoie ses documents directement.
|
||||
</div>
|
||||
|
||||
<div class="row g-4" id="qr-grid">
|
||||
<!-- QR code général -->
|
||||
<div class="col-sm-6 col-lg-4">
|
||||
<div class="card shadow-sm text-center qr-card">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title text-muted mb-1">
|
||||
<i class="bi bi-globe me-1"></i>Tous les postes
|
||||
</h6>
|
||||
<p class="small text-muted mb-3">Le client choisit le poste sur la page</p>
|
||||
<div id="qr-general" class="qr-container mb-2"></div>
|
||||
<code class="small text-break" id="url-general"></code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php foreach ($accounts as $acc): ?>
|
||||
<div class="col-sm-6 col-lg-4">
|
||||
<div class="card shadow-sm text-center qr-card">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">
|
||||
<i class="bi bi-pc-display me-1 text-primary"></i>
|
||||
<?= htmlspecialchars($acc['display_name'] ?: $acc['username']) ?>
|
||||
</h6>
|
||||
<?php if ($acc['display_name']): ?>
|
||||
<p class="small text-muted mb-3"><?= htmlspecialchars($acc['username']) ?></p>
|
||||
<?php else: ?>
|
||||
<p class="small text-muted mb-3">Accès direct à ce poste</p>
|
||||
<?php endif; ?>
|
||||
<div id="qr-<?= $acc['id'] ?>" class="qr-container mb-2"></div>
|
||||
<code class="small text-break" id="url-<?= $acc['id'] ?>"></code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.qr-card { border-radius: 12px; }
|
||||
.qr-container { display: flex; justify-content: center; }
|
||||
.qr-container canvas { border-radius: 8px; }
|
||||
|
||||
@media print {
|
||||
.navbar, .alert, .btn, .d-flex.justify-content-between .d-flex { display: none !important; }
|
||||
.col-sm-6 { break-inside: avoid; }
|
||||
.qr-card { border: 2px solid #000 !important; box-shadow: none !important; }
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
|
||||
<script>
|
||||
const BASE = window.location.origin;
|
||||
const accounts = <?= json_encode($accounts) ?>;
|
||||
|
||||
function makeQR(elementId, url, urlDisplayId) {
|
||||
new QRCode(document.getElementById(elementId), {
|
||||
text: url,
|
||||
width: 200,
|
||||
height: 200,
|
||||
colorDark: '#000000',
|
||||
colorLight: '#ffffff',
|
||||
correctLevel: QRCode.CorrectLevel.M
|
||||
});
|
||||
if (urlDisplayId) {
|
||||
document.getElementById(urlDisplayId).textContent = url;
|
||||
}
|
||||
}
|
||||
|
||||
makeQR('qr-general', BASE + '/upload.php', 'url-general');
|
||||
|
||||
accounts.forEach(acc => {
|
||||
const url = BASE + '/upload.php?to=' + encodeURIComponent(acc.username);
|
||||
makeQR('qr-' + acc.id, url, 'url-' + acc.id);
|
||||
});
|
||||
</script>
|
||||
<?php html_foot(); ?>
|
||||
Reference in New Issue
Block a user