mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-09 13:11:54 +00:00
- Sites : liste + carte Leaflet/OSM réelle (pins maquette, positions PostGIS), création en modale avec position posée au clic sur la carte - Fiche site : arbre site→zones, appareils rattachés, ajout de zone - Ascenseurs : table dense, filtres site/statut, strie rouge à l'arrêt ; fiche appareil (organes ± ajout/retrait, statut, QR réel) ; création identité → rattachement → organes ; étiquette A6 imprimable (objet papier, window.print n'imprime qu'elle) - Personnes & équipes : invitation → lien d'activation affiché à copier (pas d'email en R1, décision explicite), renvoi de lien, équipes ; page /activation (choix du mot de passe, connexion directe) - Catégories : ajout, renommage inline, désactivation - navigation et actions pilotées par la matrice (usePermissions) — l'API re-vérifie chaque requête - e2e Playwright : recette R1 officielle rejouée intégralement (site → zone → appareil+organe → étiquette → invitation → activation) + parcours « la matrice pilote l'UI » ; purge idempotente en globalSetup - alias Vite @siop/shared → source TS (exports nommés CJS ↯ workspace lié) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
77 lines
2.8 KiB
TypeScript
77 lines
2.8 KiB
TypeScript
import { QRCodeSVG } from 'qrcode.react';
|
|
import { Link, useParams } from 'react-router-dom';
|
|
import { useAsset } from '@/api/referentiel';
|
|
import { Button } from '@/components/ui/button';
|
|
|
|
/** Écran 5 des maquettes R1 : l'étiquette A6 imprimable — objet PAPIER
|
|
* (noir sur blanc, même en thème sombre). window.print n'imprime qu'elle. */
|
|
export default function PageEtiquette() {
|
|
const { id } = useParams<{ id: string }>();
|
|
const { data: asset } = useAsset(id);
|
|
if (!asset) return null;
|
|
|
|
const url = `${window.location.origin}/q/${asset.reference}`;
|
|
|
|
return (
|
|
<>
|
|
<div className="filajout">
|
|
<Link to="/ascenseurs">Ascenseurs</Link> /{' '}
|
|
<Link to={`/ascenseurs/${asset.id}`}>Ascenseur {asset.reference}</Link> / Étiquette QR
|
|
</div>
|
|
<div className="entete-page">
|
|
<h1>Étiquette cabine — Ascenseur {asset.reference}</h1>
|
|
<div className="actions">
|
|
<Button variant="prim" onClick={() => window.print()}>
|
|
Imprimer (A6)
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<div className="zone-impression">
|
|
<div className="etiquette">
|
|
<div className="tete">
|
|
<span className="marque" aria-hidden="true">▲<br />▼</span>
|
|
<b>SIOP</b>
|
|
<span style={{ marginLeft: 'auto', fontSize: 11, color: '#55647a' }}>
|
|
Maintenance d'ascenseurs
|
|
<br />
|
|
SPELEV
|
|
</span>
|
|
</div>
|
|
<div className="corps">
|
|
<QRCodeSVG className="qr-grand" value={url} size={120} marginSize={1} />
|
|
<div>
|
|
<h3>Ascenseur {asset.reference}</h3>
|
|
<div className="ou">
|
|
{asset.siteName}
|
|
<br />
|
|
{asset.locationName !== asset.siteName ? `${asset.locationName} — ` : ''}
|
|
{asset.brand} {asset.model ?? ''}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="consigne">
|
|
Un problème ? Une personne bloquée ?
|
|
<br />
|
|
📱 Scannez ce code pour signaler
|
|
</div>
|
|
<div className="ref">
|
|
SIOP · {asset.reference}
|
|
{asset.serialNumber ? ` · ${asset.serialNumber}` : ''} · {url.replace(/^https?:\/\//, '')}
|
|
</div>
|
|
</div>
|
|
<div className="carte" style={{ flex: 1, minWidth: 260 }}>
|
|
<h2>Ce que fait le scan</h2>
|
|
<dl className="infos" style={{ gridTemplateColumns: '96px 1fr' }}>
|
|
<dt>Gardien</dt>
|
|
<dd>ouvrira le <b>portail de signalement</b>, équipement prérempli (R2)</dd>
|
|
<dt>Technicien</dt>
|
|
<dd>connecté → ouvre la <b>fiche de l'appareil</b></dd>
|
|
<dt>Impression</dt>
|
|
<dd>A6 autocollant, noir sur blanc</dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|