Componenti UI — dominio job
🎯 Cosa fa
Sotto TrainingHub.BackOffice/Components/CRUD/job/ vivono i
componenti Blazor CRUD per le 19 entità del dominio. Pattern
generazione identico a inv, reg, edu: vedi
componenti UI inv per dettagli
generali.
🗺️ Entità e viste
CRUD standard
| Entità | Note |
|---|---|
Worker | Form ricco con cascade FK molteplici (company, companyLocation, role, department, riskLevel, academicQualification) |
WorkerJobHistory | Tipicamente in sola lettura, alimentato da logica di cambio mansione |
WorkersJob | Associazione lavoratore-mansione |
Job, JobGroup, JobSubcategory | Anagrafiche mansioni |
Role, Department | Anagrafiche ruoli/reparti (reparti con tree view) |
Risk, RiskLevel | Anagrafiche rischi e livelli |
AtecoCode | Tree view gerarchica |
AtecoCodeLegacy | CRUD su atecoCodesLegacy. Esposto come admin tool per popolare/aggiornare il mapping versioni precedenti → codice corrente; non parte del flusso operativo utente. Alimenta la conversione automatica nell'import aziende (TrainingHub.Import/Engines/Company.cs ClearCompanyData). |
CompaniesRisk, JobsRisk, WorkersRisk | Associazioni rischio per livello |
Viste aggregate / analitiche
| Componente | Ruolo |
|---|---|
WorkersData.razor | Vista dati lavoratori con aggregazioni |
JobsData.razor | Vista mansioni con statistiche |
WorkerEffectiveRisk.razor | Vista calcolata dei rischi finali del lavoratore (cascade applicato) |
WorkerComplianceSummary.razor | CRUD auto-generato sulla view vw_workerComplianceSummary (read-only). Mostra rollup compliance per lavoratore: badge worstStatus + conteggi + giorni residui. Embed nello step "Conformità formativa" del wizard CompanyFormPopup con filtro companyId. Vedi pattern in Architettura — view → CRUD |
Tutti e quattro sono CRUD generati su vista, non componenti custom:
WorkersData.razor:3-6 (/job/vw_workersData), JobsData.razor:3-6
(/job/vw_jobsData) e WorkerEffectiveRisk.razor:3-6
(/job/vw_workerEffectiveRisks, policy
page-job-vw_workerEffectiveRisks_R) ereditano da
Tabiot.Blazor.DxGridBase e hanno il proprio .razor.tt.cs più il conf
_conf/vw_*.dxgrid.conf.json. Un generator_run li riscrive: le
personalizzazioni vanno nel conf o nel .razor.cs, non nel .razor.
🧩 Pattern chiave job-specifici
Form Worker con molteplici FK
WorkerForm.razor contiene ~6 combobox cascade-oriented:
<EditComboBox Data="fk_companyId" ... />
<EditComboBox Data="fk_companyLocationId" ... /> <!-- filtrato per companyId -->
<EditComboBox Data="fk_departmentId" ... /> <!-- filtrato per companyId -->
<EditComboBox Data="fk_roleId" ... />
<EditComboBox Data="fk_riskLevelId" ... />
<EditComboBox Data="fk_academicQualificationId" ... />
Il filtro dinamico dei combobox "dipendenti" (companyLocation,
department filtrati per company) è logica custom nel .razor.cs. Al
cambio companyId, i combobox correlati vengono ricaricati con il
nuovo filtro.
Vista WorkerEffectiveRisk
Il cascade non è nel componente: è nella vista SQL
job.vw_workerEffectiveRisks. Il code-behind si limita a
SELECT * FROM job.fn_getWorkerRisks(@workerId)
(WorkerEffectiveRisk.razor.cs:40), con un filtro su origin <> 'none'
quando non si chiede «mostra tutti».
In sintesi, quel che fa la vista:
- Tre rami — mansione, azienda, personale — tutti su lavoratori attivi.
jobsRisks.onlyIfCompanyHasRiskgoverna il ramo mansione;jobs.inheritsCompanyRisksecompaniesRisks.onlyForExposedJobsgovernano il ramo azienda (lo filtrano, non sommano nulla): il primo dal lato mansione, il secondo dal lato rischio — un rischio marcato non si propaga a chi eredita, pur restando condizione per il ramo mansione. - Spareggio per origine:
worker>job>company. - Livello:
COALESCE(riskLevelId, companies.riskLevelId). - Gli esclusi non spariscono: tornano con
origin = 'excluded'. fn_getWorkerRisksaggiunge i rischi di catalogo non assegnati conorigin = 'none'.
Le origini sono quindi cinque: job, company, worker,
excluded, none. Dettaglio in
logica applicativa.
Utile per:
- Verifica manuale da parte del RSPP.
- Generazione bozza DVR individuale.
- Determinazione formazione richiesta (consumato da
ITrainingExpirationService).
Reparti e ATECO — nessuna tree view
Department.razor e AtecoCode.razor portano entrambi una gerarchia nei
dati (parentId e parentCode), ma in UI sono griglie piatte:
DxGridBase + <DxGrid>, con i code-behind vuoti. Nessun DxTreeView,
nessun TreeList, nessun drag-and-drop.
Derivazione del sesso dal codice fiscale
Forms/WorkerForm.razor.cs:8-12 — OnFiscalCodeChanged() fa una cosa
sola: se fiscalCode ha almeno 16 caratteri, legge i caratteri 9-10 e
imposta gender (> 40 → F, altrimenti M).
Non calcola data di nascita né luogo di nascita, non usa helper
condivisi e non valida il checksum. Non c'è nessun pulsante: il
metodo è invocato da Validate() (:36-43) insieme a
OnCompanyChanged(), quindi scatta al salvataggio.
📁 File chiave
Components/CRUD/job/Worker.razor.cs— code-behind principaleComponents/CRUD/job/Forms/WorkerForm.razor{,.cs}— form con cascade FK e auto-calcolo CFComponents/CRUD/job/WorkerEffectiveRisk.razor— vista cascade rischiComponents/CRUD/job/Department.razor+ tree view helperComponents/CRUD/job/AtecoCode.razor+ tree viewComponents/CRUD/job/_conf/*.dxgrid.conf.json— configurazione
🔌 Estensione tipica
Pattern generale come nei domini precedenti. Specificità job:
- Aggiungere un campo
worker. Molti campi esistenti richiedono logica custom nel.razor.cs(cascade FK); valutare se il nuovo campo necessita di logica o è "semplice" form field. - Aggiungere un livello di rischio. Inserire riga in
riskLevel(PK int) con label. Gli override lato UI non servono se i combobox sono già dinamici. - Modificare cascade rischi. Logica centrale in
IRiskInheritanceService: modifiche lì invece che nel UI. - Nuova vista analitica. Segui il pattern di
WorkersData/WorkerEffectiveRisk: componente Razor custom non-CRUD con@pagedirective, inject dei service necessari.
⚠️ Debito tecnico
- Cascade filtri combobox in
WorkerForm. La logica di filtro dinamico (companyLocation per company, department per company) è duplicata tra form. Valutare helper condiviso. -
WorkerEffectiveRisksenza test. Componente centrale per compliance, ma senza copertura automatica. Regressioni difficili da detect. - Vista
JobsData/WorkersData. Non è chiaro se sono "live" o cachate. Performance su dataset grandi. - Gerarchie senza rappresentazione ad albero. Reparti e ATECO
hanno un
parentId/parentCodeche la griglia piatta non mostra: l'utente non vede la struttura. Valutare unTreeListcondiviso. - Nessuna validazione del checksum CF.
WorkerForm.razor.cs:10si ferma aLength >= 16. L'algoritmo esiste già nel pacchettoMascher(repo sorelladev3sd/Mascher,Anonymization/Italian/FiscalCode.cs).
🔗 Vedi anche
- Panoramica dominio
- Schema DB
- Logica applicativa
- Dominio
inv: componenti UI — pattern CRUD base