- Catalogage rapide (douchette, code-barres)

- Cataloguer en rafale — nouvel écran /ajout/rafale : on scanne une pile de livres à la suite dans une zone de texte, chaque code est traité (BnF puis OpenLibrary), les doublons connus sont passés automatiquement. La collecte marche même hors-ligne. Le compte rendu liste maintenant les livres créés, en lien vers leur fiche, et reste consultable en revenant sur l'écran même après une rafale entièrement réussie. Le catalogue reconnaît un ISBN dans sa barre de recherche (13 ou 10 chiffres, avec ou sans tirets) : scanner un livre en main ouvre directement sa fiche s'il n'y en a qu'un. Un bouton « Scanner » l'alimente, actif hors-ligne.
- Ajouter un tome à une série accepte aussi un ISBN dans le champ manuel : le catalogue est cherché d'abord (rattachement direct si un seul exemplaire), sinon la BnF prend le relais.
Séries et sagas
- Numéro de tome distinct de la position de lecture : on peut indiquer « c'est le tome 7 » même si on ne possède pas les six premiers ; l'ordre de lecture reste un réglage séparé (utile pour les préquelles).
- Tri par numéro en plus du tri par ordre de lecture quand des tomes en portent un.
- Panneau « Ajouter » regroupé et repliable sur la fiche d'une série (manuellement / en rafale / depuis le catalogue / depuis les envies), au lieu de quatre formulaires ouverts en permanence.
- Filtre catalogue « sans couverture » pour repérer les livres à illustrer.
Le catalogue groupe les tomes d'une même série sous un bloc repliable, avec un décompte plus clair (affichés / possédés / total).
- Corrections directes sur la fiche
- Effacer un prêt saisi par erreur (bouton ✕ sur chaque ligne, avec confirmation), sans passer par « rendre ».
- Corriger une couverture manquante ou cassée en cliquant dessus : le champ d'adresse s'ouvre focalisé, Entrée enregistre. Étendu aux numéros de revue dans la dernière modification.
- Les thèmes déjà utilisés dans la bibliothèque sont proposés à la frappe.
- La recherche d'un livre à rattacher montre des suggestions dès le focus, sans attendre de taper.

- Visuel : un rendu manquant après une écriture asynchrone dans le formulaire de livre, une bascule de rôle cassée, des débordements à 320 px, et le style d'un bouton-lien qui restait souligné.
This commit is contained in:
mathieu
2026-09-09 00:05:26 +02:00
parent bb071c3db9
commit 42dec0dbd1
43 changed files with 4154 additions and 189 deletions
+50 -1
View File
@@ -72,6 +72,10 @@
question. *@
<a class="bouton bouton-discret" href="ajout/manuel">Saisir un livre</a>
<a class="bouton bouton-discret" href="revues/ajout">Saisir une revue</a>
@* Une pile de livres et une douchette : on collecte d'abord, on traite ensuite.
Reste ici, et non dans le menu : c'est une façon d'ajouter, pas une destination. *@
<a class="bouton bouton-discret" href="ajout/rafale">Cataloguer en rafale</a>
</div>
}
@@ -225,7 +229,29 @@
private EnregistrementLivre _saisie = new();
private DoublonsLivre? _doublons;
protected override void OnInitialized() => Reseau.Change += SurChangementReseau;
/// <summary>
/// Code transmis par un autre écran — un résidu de rafale à trancher.
/// </summary>
/// <remarks>
/// ⚠️ La recherche s'enchaîne d'elle-même, comme après un scan : arriver ici depuis un
/// compte rendu de rafale signifie qu'on a déjà décidé de reprendre ce code. Demander un
/// clic de plus sur « Chercher » serait le détour que cet écran documente déjà comme un
/// défaut (voir l'étape « Recherche »).
/// </remarks>
[SupplyParameterFromQuery(Name = "code")]
public string? CodePropose { get; set; }
protected override void OnInitialized()
{
Reseau.Change += SurChangementReseau;
if (!string.IsNullOrWhiteSpace(CodePropose))
{
_isbn = CodePropose.Trim();
}
}
private bool _repriseFaite;
/// <summary>
/// Donne le focus au champ ISBN dès que l'étape de saisie s'affiche.
@@ -237,6 +263,29 @@
/// </remarks>
protected override async Task OnAfterRenderAsync(bool premierRendu)
{
// ⚠️ AVANT le garde de focus ci-dessous, qui rend la main dès que le focus est posé :
// greffée après, la reprise ne serait jouée qu'une fois sur deux, selon l'étape.
//
// ⚠️ Et surtout PAS conditionnée à `premierRendu` : au premier rendu, l'état réseau
// n'est pas encore établi (il s'initialise de façon asynchrone), donc `EnLigne` est
// faux et la reprise ne partait jamais. Constaté à l'écran — le champ se préremplissait
// bien, la recherche ne s'enchaînait pas. C'est `_repriseFaite` qui garantit l'unicité,
// pas le premier rendu ; l'événement réseau provoque le rendu où la condition passe.
if (!_repriseFaite && !string.IsNullOrWhiteSpace(CodePropose) && Reseau.EnLigne)
{
_repriseFaite = true;
await ChercherAsync();
// ⚠️ `StateHasChanged` est INDISPENSABLE ici, et son absence ne se voit pas :
// `OnAfterRenderAsync` n'est pas un gestionnaire d'événement, donc Blazor ne
// redessine rien de lui-même. La recherche partait bien — sonde à l'appui — et
// remplissait `_candidats`, mais l'écran restait sur l'étape de saisie.
// Même famille que « un composant qui écrit dans un objet prêté doit prévenir son
// parent » : le symptôme trompe, on cherche un appel qui n'a pas eu lieu là où il
// n'y a qu'un rendu manquant.
StateHasChanged();
}
if (_etape != Etape.Saisie || !_focusAFaire)
{
return;