1/** 2 * tec-impianti-vista-luogo.js â v20.373.118 3 * 4 * ââ LA REGOLA ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 5 * UN IMPIANTO STA NELL'EDIFICIO CHE LO CONTIENE â e il DVR lo racconta DOVE STA. 6 * 7 * tec-impianti-luogo-migrazione.js ha gia' stabilito che gli impianti vivono nel Luogo. Da li' 8 * syncImpiantiGrafoToSede produce una proiezione piatta di sede (d.imp*) che serve ai lettori 9 * legacy (readiness, profilo). Quella proiezione e' UNO SPECCHIO, non la fonte, e ha un limite 10 * strutturale che non e' un bug da tappare ma una conseguenza della sua forma: e' UN record per 11 * N edifici. Se la palazzina uffici ha la DiCo e il capannone no, un record solo puo' raccontare 12 * un fatto solo â e il fatto che sopravvive e' quello del luogo che arriva prima. 13 * 14 * Verificato in laboratorio, non dedotto (due luoghi, impianti divergenti): 15 * luogo A: DiCo presente, luce emergenza si, idrico antincendio no 16 * luogo B: DiCo MANCANTE, luce emergenza NO, idrico antincendio si (idranti UNI45) 17 * §1.4 stampava: «DiCo D.M. 37/08 presente», «Emergenza: presente», «Assenti: idrico 18 * antincendio» â mentre d.impIdricoAI_tipo valeva 'idranti_uni45'. Due non conformita' 19 * cancellate e un record impossibile (assente + con idranti) prodotto dalla fusione. 20 * 21 * Questo modulo e' il proprietario unico della vista impianti PER LUOGO. Non duplica la 22 * presentazione: proietta ogni singolo luogo nella stessa forma piatta che i lettori conoscono 23 * e la passa allo stesso identico costruttore (buildImpiantiDettaglioExport). Un solo motore, 24 * N inquadrature. 25 * 26 * Dichiara anche le DIVERGENZE: dove i luoghi non dicono la stessa cosa, il documento lo scrive. 27 * Il silenzio non assolve (art. 29 c.1). 28 */ 29(function (g) { 30 'use strict'; 31 var VERSION = '1.0.0'; 32 33 function _S() { return g._tecImpiantiSync || null; } 34 function _EC() { return g._tecDvrExportClarity || null; } 35 36 function _hasVal(v) { 37 if (v == null) return false; 38 if (typeof v === 'string') return v.trim() !== '' && v.trim() !== 'â'; 39 if (typeof v === 'number') return !isNaN(v); 40 if (typeof v === 'boolean') return true; 41 return false; 42 } 43 function _s(v) { return v == null ? '' : String(v).trim(); } 44 45 /** 46 * Etichette leggibili delle chiavi piatte. Non inventate: derivate da UI_BLOCKS, cioe' dalle 47 * stesse parole che il tecnico legge sullo schermo mentre compila. Se una chiave non ha 48 * etichetta dichiarata NON si indovina: si restituisce la chiave, cosi' il buco si vede. 49 */ 50 function mappaEtichette() { 51 var S = _S(); 52 var out = {}; 53 if (!S || !S.BLOCKS) return out; 54 var ui = S.UI_BLOCKS || []; 55 Object.keys(S.BLOCKS).forEach(function (bk) { 56 var def = S.BLOCKS[bk] || {}; 57 var gk = def.grafoKeys || {}; 58 var uiB = null; 59 for (var i = 0; i < ui.length; i++) { if (ui[i] && ui[i].key === bk) { uiB = ui[i]; break; } } 60 var etBlocco = (uiB && uiB.label) ? uiB.label : bk; 61 Object.keys(gk).forEach(function (sedeK) { 62 var campoGrafo = gk[sedeK]; 63 var lab = ''; 64 if (uiB && uiB.fields) { 65 for (var j = 0; j < uiB.fields.length; j++) { 66 if (uiB.fields[j] && uiB.fields[j].k === campoGrafo) { lab = uiB.fields[j].l; break; } 67 } 68 } 69 if (!lab && uiB && campoGrafo === (uiB.presentKey || 'presente')) lab = 'Presenza impianto'; 70 out[sedeK] = { blocco: bk, etichettaBlocco: etBlocco, etichetta: lab || sedeK, campoGrafo: campoGrafo }; 71 }); 72 }); 73 return out; 74 } 75 76 /** L'elenco dei luoghi. Una sola domanda, una sola risposta: si chiede a chi la possiede gia'. */ 77 function luoghi(d, listOverride) { 78 if (Array.isArray(listOverride) && listOverride.length) return listOverride.filter(Boolean); 79 var PR = g._tecPorteReiLuogo; 80 if (PR && typeof PR.getLuoghiSync === 'function') { 81 try { var l = PR.getLuoghiSync(); if (l && l.length) return l.filter(Boolean); } catch (_e) {} 82 } 83 if (d && Array.isArray(d.ambientiSede) && d.ambientiSede.length) return d.ambientiSede.filter(Boolean); 84 var G = g._tecGrafo; 85 if (G && G.getGrafoCache) {
86 try { 87 var c = G.getGrafoCache(); 88 if (c && c.luoghiSede && c.luoghiSede.length) return c.luoghiSede.filter(Boolean); 89 if (c && c.ambientiSede && c.ambientiSede.length) return c.ambientiSede.filter(Boolean); 90 } catch (_e2) {} 91 } 92 return []; 93 } 94 95 /** Proiezione piatta di UN SOLO luogo: la stessa forma della sede, ma di un edificio solo. */ 96 function flatDiLuogo(amb) { 97 var S = _S(); 98 var out = {}; 99 if (!S || !S.BLOCKS || !S.sedeFromGrafoBlock || !amb) return out; 100 var imp = amb.impianti || {}; 101 Object.keys(S.BLOCKS).forEach(function (bk) { 102 var part = S.sedeFromGrafoBlock(bk, imp[bk]); 103 Object.keys(part).forEach(function (k) { if (_hasVal(part[k])) out[k] = part[k]; }); 104 }); 105 return out; 106 } 107 108 function haImpianti(amb) { 109 var f = flatDiLuogo(amb); 110 return Object.keys(f).length > 0; 111 } 112 113 function nomeLuogo(amb, i) { 114 return _s(amb && (amb.nome || amb.denominazione || amb.label)) || ('Luogo ' + (i + 1)); 115 } 116 117 function pianoLuogo(amb, d) { 118 var DV = g._tecLuogoDove; 119 if (DV && typeof DV.pianiDelLuogo === 'function') { 120 try { 121 var p = DV.pianiDelLuogo(amb, d); 122 if (p && p.ereditato) return p.ereditato; 123 } catch (_e) {} 124 } 125 return ''; 126 } 127 128 /** 129 * La vista. Un blocco per luogo, costruito dallo stesso motore che costruisce quello di sede. 130 * @returns {{luoghi:Array, divergenze:Array, nLuoghi:number, perLuogo:boolean, fonte:string}} 131 */ 132 function vistaPerLuogo(d, helpers, listOverride) { 133 d = d || {}; 134 helpers = helpers || {}; 135 var EC = _EC(); 136 var list = luoghi(d, listOverride).filter(haImpianti); 137 var out = { luoghi: [], divergenze: [], nLuoghi: list.length, perLuogo: false, fonte: 'grafo (impianti del luogo)' }; 138 if (!EC || typeof EC.buildImpiantiDettaglioExport !== 'function') { out.fonte = 'motore di presentazione non disponibile'; return out; } 139 list.forEach(function (amb, i) { 140 var flat = flatDiLuogo(amb); 141 var built = EC.buildImpiantiDettaglioExport(flat, helpers); 142 out.luoghi.push({ 143 id: _s(amb && amb.id) || ('l' + i), 144 nome: nomeLuogo(amb, i), 145 piano: pianoLuogo(amb, d), 146 rows: (built && built.rows) || [], 147 assentiNote: (built && built.assentiNote) || null, 148 nCampi: Object.keys(flat).length 149 }); 150 }); 151 out.divergenze = divergenze(d, list); 152 // Una sola inquadratura basta solo se c'e' un solo edificio con impianti. Con due o piu', 153 // raccontarne uno solo significa scegliere quale non conformita' nascondere. 154 out.perLuogo = list.length > 1; 155 return out; 156 } 157 158 /** 159 * Dove i luoghi non dicono la stessa cosa. Confronta le proiezioni piatte campo per campo: 160 * ogni chiave su cui almeno due luoghi portano valori diversi e' una divergenza. 161 */ 162 function divergenze(d, listOverride) { 163 var list = (Array.isArray(listOverride) ? listOverride : luoghi(d)).filter(haImpianti); 164 var et = mappaEtichette(); 165 var perCampo = {}; 166 list.forEach(function (amb, i) { 167 var flat = flatDiLuogo(amb); 168 Object.keys(flat).forEach(function (k) { 169 perCampo[k] = perCampo[k] || []; 170 perCampo[k].push({ luogo: nomeLuogo(amb, i), id: _s(amb && amb.id), valore: _s(flat[k]) }); 171 }); 172 }); 173 var out = []; 174 Object.keys(perCampo).forEach(function (k) { 175 var vals = perCampo[k]; 176 var distinti = {}; 177 vals.forEach(function (v) { distinti[v.valore] = true; }); 178 if (Object.keys(distinti).length < 2) return; 179 var meta = et[k] || { etichetta: k, etichettaBlocco: '', blocco: '' }; 180 out.push({ 181 campo: k, 182 blocco: meta.blocco, 183 etichettaBlocco: meta.etichettaBlocco, 184 etichetta: meta.etichetta, 185 valori: vals 186 }); 187 }); 188 out.sort(function (a, b) { 189 if (a.etichettaBlocco !== b.etichettaBlocco) return a.etichettaBlocco < b.etichettaBlocco ? -1 : 1; 190 return a.etichetta < b.etichetta ? -1 : 1; 191 }); 192 return out; 193 } 194 195 /** 196 * L'avvertenza che accompagna la sintesi di sede quando i luoghi divergono. Non e' una nota di 197 * stile: e' la dichiarazione che la riga di sintesi NON e' la fotografia di tutti gli edifici. 198 */ 199 function avvisoDivergenze(div) { 200 div = div || []; 201 if (!div.length) return null; 202 var campi = div.slice(0, 6).map(function (x) { 203 return x.etichetta + ' (' + x.valori.map(function (v) { return v.luogo + ': ' + (v.valore || 'â'); }).join(' · ') + ')'; 204 }); 205 return 'Gli impianti differiscono da un edificio all\'altro: il dettaglio per luogo di lavoro ' 206 + 'riportato qui sopra e\' la fonte, la sintesi di sede e\' una proiezione e non puo\' rappresentare ' 207 + 'tutti gli edifici contemporaneamente. Campi divergenti: ' + campi.join('; ') 208 + (div.length > 6 ? ('; e altri ' + (div.length - 6)) : '') + '.'; 209 } 210 211 /** Self-test in-processo: la vista non fonde, non inventa, non perde una non conformita'. */ 212 function selfTest() { 213 var errs = []; 214 var list = [ 215 { id: 'A', nome: 'Palazzina Uffici', impianti: { 216 elettrico: { presente: 'si', ubicQEgen: 'atrio', dichConf: 'presente' }, 217 illuminazione: { sicurezzaPresente: 'si', sicurezzaTipo: 'autonoma' }, 218 idricoAntincendio: { presente: 'no' } } }, 219 { id: 'B', nome: 'Capannone', impianti: { 220 elettrico: { presente: 'si', ubicQEgen: 'locale_tecnico', dichConf: 'mancante' }, 221 illuminazione: { sicurezzaPresente: 'no' }, 222 idricoAntincendio: { presente: 'si', tipo: 'idranti_uni45' } } } 223 ]; 224 var v = vistaPerLuogo({}, {}, list); 225 if (v.luoghi.length !== 2) errs.push('attesi 2 luoghi, trovati ' + v.luoghi.length); 226 if (!v.perLuogo) errs.push('con 2 edifici la vista deve essere per luogo'); 227 var testoB = (v.luoghi[1] ? v.luoghi[1].rows : []).map(function (r) { return r[1]; }).join(' | '); 228 if (testoB.indexOf('MANCANTE') < 0) errs.push('la DiCo mancante del capannone non compare'); 229 var testoA = (v.luoghi[0] ? v.luoghi[0].rows : []).map(function (r) { return r[1]; }).join(' | '); 230 if (testoA.indexOf('MANCANTE') >= 0) errs.push('la DiCo mancante e finita sulla palazzina'); 231 if (testoB.indexOf('ASSENTE') < 0) errs.push('la luce di emergenza assente del capannone non compare'); 232 var d1 = v.divergenze.filter(function (x) { return x.campo === 'impEl_dichConf'; })[0]; 233 if (!d1) errs.push('divergenza su impEl_dichConf non rilevata'); 234 return { ok: errs.length === 0, errors: errs }; 235 } 236 237 g._tecImpiantiVistaLuogo = { 238 VERSION: VERSION, 239 luoghi: luoghi, 240 flatDiLuogo: flatDiLuogo, 241 haImpianti: haImpianti, 242 nomeLuogo: nomeLuogo, 243 pianoLuogo: pianoLuogo, 244 mappaEtichette: mappaEtichette, 245 vistaPerLuogo: vistaPerLuogo, 246 divergenze: divergenze, 247 avvisoDivergenze: avvisoDivergenze, 248 selfTest: selfTest 249 }; 250})(typeof window !== 'undefined' ? window : this);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.