Marcel0123 commited on
Commit
cd7a39d
·
verified ·
1 Parent(s): 522e438

Upload index.html

Browse files
Files changed (1) hide show
  1. index.html +56 -4
index.html CHANGED
@@ -158,6 +158,10 @@
158
  .report-definitions-note{font-size:9px;color:#52618d;margin-top:5px}
159
  @media(max-width:1000px){.report-definitions-grid{grid-template-columns:1fr}}
160
  @media print{#reportSheet .report-definitions-grid{grid-template-columns:repeat(3,minmax(0,1fr))!important}#reportSheet .report-definitions{padding:4px 7px!important;margin:1px 0 6px!important}#reportSheet .report-definitions-grid>div{font-size:7px!important;line-height:1.2!important}#reportSheet .report-definitions-grid b,#reportSheet .report-definitions-title{font-size:8px!important}#reportSheet .report-definitions-note{font-size:7px!important}}
 
 
 
 
161
  </style></head>
162
  <body>
163
  <div class="app">
@@ -197,6 +201,21 @@
197
  </section>
198
  <div class="charts-grid"><section class="panel chart-panel"><div class="panel-heading"><div><span class="section-kicker">TRENDANALYSE</span><h3>Bezoeken per locatie</h3></div><span class="subtle">Jul – Sep 2026</span></div><canvas id="chart" width="640" height="250" aria-label="Grafiek fictieve bezoeken per locatie"></canvas><div class="legend"><span><i style="background:#3ee1b6"></i> Soeda</span><span><i style="background:#ffc66a"></i> Rietdijk</span><span><i style="background:#5b9cff"></i> Vredehof</span><span><i style="background:#ad88ff"></i> Gouda</span></div></section>
199
  <section class="panel verification"><div class="panel-heading"><div><span class="section-kicker">KWALITEITSBORGING</span><h3>Verificatie Businesscontroller</h3></div><span class="warn-label">DEMO</span></div><div id="checks" class="checks"></div><div class="warning">⚠ 1 fictieve afwijking. Rapport niet gevalideerd.</div></section></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  <section class="panel logpanel"><div class="panel-heading"><div><span class="section-kicker">REAL-TIME PROCESS</span><h3>Agent activity log</h3></div><span class="subtle" id="logStatus">Stand-by</span></div><div class="logs" id="logs"><div class="logitem muted">◌ &nbsp; Klik op ‘Start demo-analyse’ om de workflow te bekijken.</div></div></section>
201
  </div>
202
  <aside class="right-content"><section class="panel chatpanel"><div class="panel-heading"><div><span class="section-kicker">MANAGEMENT ASSISTENT</span><h3><span class="chat-icon">✧</span> Vraag het aan Inloop AI</h3></div><span class="demo-badge">DEMO</span></div><div class="chat-messages" id="messages"><div class="message assistant"><small>INLOOP AI · DEMONSTRATIE</small><p>Welkom! Start de demo-analyse en stel daarna een vraag over de fictieve locatiecijfers.</p></div></div><div class="quick-questions"><button data-q="Welke locatie groeit het sterkst?">Grootste groei?</button><button data-q="Zijn de cijfers gevalideerd?">Validatiestatus?</button><button data-q="Maak een managementsamenvatting">Samenvatting?</button></div><form id="chatForm" class="chat-form"><input id="chatInput" autocomplete="off" placeholder="Stel een vraag over de demo..." aria-label="Vraag aan Inloop AI"><button aria-label="Verstuur vraag">➤</button></form><div class="chat-disclaimer">Vooraf ingestelde demo-antwoorden · geen echte AI</div></section>
@@ -206,7 +225,7 @@
206
  </main>
207
  </div>
208
  <div id="reportOverlay" role="dialog" aria-modal="true" aria-label="Reakt Monitor rapport" aria-hidden="true">
209
- <div class="report-actions"><span><strong>REAKT · Rapportvoorvertoning v1.1</strong> &nbsp; — uitsluitend fictieve testgegevens</span><div><button id="reportClose" type="button">✕ Sluiten</button> <button id="reportPng" class="report-png" type="button">⬇ Download PNG</button> <button id="reportJpg" class="report-jpg" type="button">⬇ Download JPG</button> <button id="reportPrint" class="report-print" type="button">↓ Opslaan als PDF / Afdrukken</button></div></div>
210
  <section id="reportSheet" aria-label="Witte Inloop Monitor"></section>
211
  </div>
212
  <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
@@ -606,6 +625,7 @@ async function startImported(){
606
  {agent:'verify',text:`${result.verification.checks.length} onafhankelijke interne telcontroles; ${result.verification.mismatches} afwijkingen; ${result.verification.sourceIssues.length} soorten bronproblemen. Extern niet gevalideerd`},
607
  {agent:'report',text:'Conceptpreview bijgewerkt · NIET GEVALIDEERD'}];
608
  try{
 
609
  renderImported(result);
610
  for(const step of steps){const el=$('agent-'+step.agent);signalFor(step.agent);el.classList.add('active');el.querySelector('.status').textContent='ACTIEF';$('flowState').textContent=step.text;log('Start: '+el.querySelector('h3').textContent);
611
  const stageLabels=stepDescriptions(step.agent,{...result,sites:importedData.sites.length},false);showStages(step.agent,stageLabels);await animateStages(step.agent,stageLabels);
@@ -615,7 +635,7 @@ async function startImported(){
615
  }catch(err){log('FOUT: '+err.message);$('flowState').textContent='Proefberekening mislukt';}finally{clearSignal();running=false;$('startBtn').disabled=false;$('resetBtn').disabled=false;$('conductor').classList.remove('running');document.querySelector('.orchestra').classList.remove('running')}
616
  }
617
  $('scanFile').addEventListener('change',async e=>{
618
- importedData=null;const file=e.target.files?.[0];if(!file)return;
619
  const state=$('importState');state.textContent='Bestand wordt lokaal gelezen...';$('startBtn').disabled=true;
620
  try{
621
  importedData=await readExcelLocal(file);
@@ -632,8 +652,8 @@ $('scanFile').addEventListener('change',async e=>{
632
  log('Fictief Excel-testbestand is lokaal ingelezen; nog geen berekeningen gepubliceerd');
633
  }catch(err){$('startBtn').textContent='▶ Start demo-analyse';state.textContent='⚠ '+err.message;$('siteSelect').disabled=true;$('periodSelect').disabled=true;log('Excel-proef: '+err.message)}finally{$('startBtn').disabled=false}
634
  });
635
- $('siteSelect').addEventListener('change',()=>{if(importedData){importedData.last=null;$('flowState').textContent='Locatie gewijzigd · analyse opnieuw starten';}});
636
- $('periodSelect').addEventListener('change',()=>{if(importedData){importedData.last=null;$('flowState').textContent='Kwartaal gewijzigd · analyse opnieuw starten';}});
637
  // Bestaande chat blijft demo-gericht. Voor echte Excel-proef antwoorden we uitsluitend met controleerbare berekende cijfers.
638
  const originalReply=reply;
639
  reply=function(q){
@@ -783,4 +803,36 @@ document.addEventListener('keydown',e=>{if(e.key==='Escape'&&$('reportOverlay').
783
  $('startBtn').addEventListener('click',start);$('resetBtn').addEventListener('click',reset);$('chatForm').addEventListener('submit',e=>{e.preventDefault();const q=$('chatInput').value;$('chatInput').value='';ask(q)});document.querySelectorAll('[data-q]').forEach(b=>b.addEventListener('click',()=>ask(b.dataset.q)));$('exportBtn').addEventListener('click',openWhiteReport);
784
  Promise.resolve({ok:true,json:async()=>JSON.parse(document.getElementById('orchestra-demo-data').textContent)}).then(r=>r.json()).then(d=>{demoData=d;renderKPIs(d);renderChecks(d);drawChart(d)}).catch(()=>log('Demo-gegevens konden niet worden geladen'));
785
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
786
  </script></body></html>
 
158
  .report-definitions-note{font-size:9px;color:#52618d;margin-top:5px}
159
  @media(max-width:1000px){.report-definitions-grid{grid-template-columns:1fr}}
160
  @media print{#reportSheet .report-definitions-grid{grid-template-columns:repeat(3,minmax(0,1fr))!important}#reportSheet .report-definitions{padding:4px 7px!important;margin:1px 0 6px!important}#reportSheet .report-definitions-grid>div{font-size:7px!important;line-height:1.2!important}#reportSheet .report-definitions-grid b,#reportSheet .report-definitions-title{font-size:8px!important}#reportSheet .report-definitions-note{font-size:7px!important}}
161
+
162
+ /* v1.2: los, compact controlepaneel; bestaande ORCHESTRA en rapport-opmaak ongewijzigd */
163
+ .controller-panel{padding:17px}.controller-note,.controller-footer{font-size:11px;line-height:1.55;color:#a8bad5;margin:6px 0 12px}.controller-context{border:1px solid #345075;background:#102642;border-radius:7px;padding:9px 12px;color:#b5d5f5;font-size:11px;margin-bottom:12px}
164
+ .controller-entry{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}.controller-entry label{display:flex;flex-direction:column;gap:7px;color:#b5c6dd;font-size:10px}.controller-entry input{width:100%;min-width:0;background:#0a1528;border:1px solid #365579;border-radius:7px;padding:10px;color:#f2f7ff;font-size:14px}.controller-entry input:focus{outline:1px solid #8e8bff}.controller-actions{display:flex;gap:9px;margin:12px 0}.controller-result{font-size:11px;color:#a9bfda}.controller-table{width:100%;border-collapse:collapse;margin-top:8px;font-size:11px}.controller-table th,.controller-table td{text-align:right;padding:9px 7px;border-bottom:1px solid #28415e}.controller-table th:first-child,.controller-table td:first-child{text-align:left}.controller-table th{color:#94b4dc;font-weight:600}.controller-ok{color:#57edb7;font-weight:700}.controller-bad{color:#ffb37b;font-weight:700}.controller-summary{padding:10px 12px;border-radius:7px;border:1px solid #5a5b79;background:#23243d;margin:10px 0}.controller-footer{margin-bottom:0}.controller-note strong{color:#eaf4ff}@media(max-width:800px){.controller-entry{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:460px){.controller-entry{grid-template-columns:1fr}}
165
  </style></head>
166
  <body>
167
  <div class="app">
 
201
  </section>
202
  <div class="charts-grid"><section class="panel chart-panel"><div class="panel-heading"><div><span class="section-kicker">TRENDANALYSE</span><h3>Bezoeken per locatie</h3></div><span class="subtle">Jul – Sep 2026</span></div><canvas id="chart" width="640" height="250" aria-label="Grafiek fictieve bezoeken per locatie"></canvas><div class="legend"><span><i style="background:#3ee1b6"></i> Soeda</span><span><i style="background:#ffc66a"></i> Rietdijk</span><span><i style="background:#5b9cff"></i> Vredehof</span><span><i style="background:#ad88ff"></i> Gouda</span></div></section>
203
  <section class="panel verification"><div class="panel-heading"><div><span class="section-kicker">KWALITEITSBORGING</span><h3>Verificatie Businesscontroller</h3></div><span class="warn-label">DEMO</span></div><div id="checks" class="checks"></div><div class="warning">⚠ 1 fictieve afwijking. Rapport niet gevalideerd.</div></section></div>
204
+
205
+ <section class="panel controller-panel" id="controllerPanel" aria-label="Vergelijking met businesscontroller">
206
+ <div class="panel-heading"><div><span class="section-kicker">EXTERNE SCHADUWCONTROLE · FICTIEVE TEST</span><h3>Vergelijk met businesscontroller</h3></div><span class="warn-label" id="controllerBadge">NIET AANGELEVERD</span></div>
207
+ <p class="controller-note">Vul uitsluitend <strong>fictieve, geaggregeerde</strong> controlecijfers in voor exact dezelfde locatie, periode en definities. Geen cliëntgegevens. Invoer blijft in deze browserpagina en wordt niet opgeslagen.</p>
208
+ <div class="controller-context" id="controllerContext">Analyseer eerst het fictieve Excel-bestand en kies een locatie en kwartaal.</div>
209
+ <div class="controller-entry" id="controllerFields">
210
+ <label>Unieke cliënten (historie)<input id="ctrlUnique" type="number" min="0" step="1" inputmode="numeric" placeholder="Bijv. 18"></label>
211
+ <label>Nieuwe instroom (kwartaal)<input id="ctrlIntake" type="number" min="0" step="1" inputmode="numeric" placeholder="Bijv. 14"></label>
212
+ <label>Actieve cliënten (3 maanden)<input id="ctrlActive" type="number" min="0" step="1" inputmode="numeric" placeholder="Bijv. 17"></label>
213
+ <label>Unieke bezoekdagen (kwartaal)<input id="ctrlVisits" type="number" min="0" step="1" inputmode="numeric" placeholder="Bijv. 49"></label>
214
+ </div>
215
+ <div class="controller-actions"><button id="controllerCompare" class="primary" type="button">↔ Vergelijk cijfers</button><button id="controllerClear" class="ghost" type="button">Wissen</button></div>
216
+ <div id="controllerResult" class="controller-result" aria-live="polite">Nog geen onafhankelijke controlecijfers vergeleken.</div>
217
+ <div class="controller-footer">Interne controles en vergelijking met ingevoerde waarden zijn afzonderlijk. Een overeenkomst geldt niet als formele validatie of vrijgave.</div>
218
+ </section>
219
  <section class="panel logpanel"><div class="panel-heading"><div><span class="section-kicker">REAL-TIME PROCESS</span><h3>Agent activity log</h3></div><span class="subtle" id="logStatus">Stand-by</span></div><div class="logs" id="logs"><div class="logitem muted">◌ &nbsp; Klik op ‘Start demo-analyse’ om de workflow te bekijken.</div></div></section>
220
  </div>
221
  <aside class="right-content"><section class="panel chatpanel"><div class="panel-heading"><div><span class="section-kicker">MANAGEMENT ASSISTENT</span><h3><span class="chat-icon">✧</span> Vraag het aan Inloop AI</h3></div><span class="demo-badge">DEMO</span></div><div class="chat-messages" id="messages"><div class="message assistant"><small>INLOOP AI · DEMONSTRATIE</small><p>Welkom! Start de demo-analyse en stel daarna een vraag over de fictieve locatiecijfers.</p></div></div><div class="quick-questions"><button data-q="Welke locatie groeit het sterkst?">Grootste groei?</button><button data-q="Zijn de cijfers gevalideerd?">Validatiestatus?</button><button data-q="Maak een managementsamenvatting">Samenvatting?</button></div><form id="chatForm" class="chat-form"><input id="chatInput" autocomplete="off" placeholder="Stel een vraag over de demo..." aria-label="Vraag aan Inloop AI"><button aria-label="Verstuur vraag">➤</button></form><div class="chat-disclaimer">Vooraf ingestelde demo-antwoorden · geen echte AI</div></section>
 
225
  </main>
226
  </div>
227
  <div id="reportOverlay" role="dialog" aria-modal="true" aria-label="Reakt Monitor rapport" aria-hidden="true">
228
+ <div class="report-actions"><span><strong>REAKT · Rapportvoorvertoning v1.2</strong> &nbsp; — uitsluitend fictieve testgegevens</span><div><button id="reportClose" type="button">✕ Sluiten</button> <button id="reportPng" class="report-png" type="button">⬇ Download PNG</button> <button id="reportJpg" class="report-jpg" type="button">⬇ Download JPG</button> <button id="reportPrint" class="report-print" type="button">↓ Opslaan als PDF / Afdrukken</button></div></div>
229
  <section id="reportSheet" aria-label="Witte Inloop Monitor"></section>
230
  </div>
231
  <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
 
625
  {agent:'verify',text:`${result.verification.checks.length} onafhankelijke interne telcontroles; ${result.verification.mismatches} afwijkingen; ${result.verification.sourceIssues.length} soorten bronproblemen. Extern niet gevalideerd`},
626
  {agent:'report',text:'Conceptpreview bijgewerkt · NIET GEVALIDEERD'}];
627
  try{
628
+ resetControllerComparison(true);updateControllerContext();
629
  renderImported(result);
630
  for(const step of steps){const el=$('agent-'+step.agent);signalFor(step.agent);el.classList.add('active');el.querySelector('.status').textContent='ACTIEF';$('flowState').textContent=step.text;log('Start: '+el.querySelector('h3').textContent);
631
  const stageLabels=stepDescriptions(step.agent,{...result,sites:importedData.sites.length},false);showStages(step.agent,stageLabels);await animateStages(step.agent,stageLabels);
 
635
  }catch(err){log('FOUT: '+err.message);$('flowState').textContent='Proefberekening mislukt';}finally{clearSignal();running=false;$('startBtn').disabled=false;$('resetBtn').disabled=false;$('conductor').classList.remove('running');document.querySelector('.orchestra').classList.remove('running')}
636
  }
637
  $('scanFile').addEventListener('change',async e=>{
638
+ importedData=null;resetControllerComparison(true);updateControllerContext();const file=e.target.files?.[0];if(!file)return;
639
  const state=$('importState');state.textContent='Bestand wordt lokaal gelezen...';$('startBtn').disabled=true;
640
  try{
641
  importedData=await readExcelLocal(file);
 
652
  log('Fictief Excel-testbestand is lokaal ingelezen; nog geen berekeningen gepubliceerd');
653
  }catch(err){$('startBtn').textContent='▶ Start demo-analyse';state.textContent='⚠ '+err.message;$('siteSelect').disabled=true;$('periodSelect').disabled=true;log('Excel-proef: '+err.message)}finally{$('startBtn').disabled=false}
654
  });
655
+ $('siteSelect').addEventListener('change',()=>{if(importedData){importedData.last=null;resetControllerComparison(true);updateControllerContext();$('flowState').textContent='Locatie gewijzigd · analyse opnieuw starten';}});
656
+ $('periodSelect').addEventListener('change',()=>{if(importedData){importedData.last=null;resetControllerComparison(true);updateControllerContext();$('flowState').textContent='Kwartaal gewijzigd · analyse opnieuw starten';}});
657
  // Bestaande chat blijft demo-gericht. Voor echte Excel-proef antwoorden we uitsluitend met controleerbare berekende cijfers.
658
  const originalReply=reply;
659
  reply=function(q){
 
803
  $('startBtn').addEventListener('click',start);$('resetBtn').addEventListener('click',reset);$('chatForm').addEventListener('submit',e=>{e.preventDefault();const q=$('chatInput').value;$('chatInput').value='';ask(q)});document.querySelectorAll('[data-q]').forEach(b=>b.addEventListener('click',()=>ask(b.dataset.q)));$('exportBtn').addEventListener('click',openWhiteReport);
804
  Promise.resolve({ok:true,json:async()=>JSON.parse(document.getElementById('orchestra-demo-data').textContent)}).then(r=>r.json()).then(d=>{demoData=d;renderKPIs(d);renderChecks(d);drawChart(d)}).catch(()=>log('Demo-gegevens konden niet worden geladen'));
805
 
806
+
807
+ // v1.2 — expliciete, handmatig ingevoerde onafhankelijke fictieve aggregaten.
808
+ // Resultaten worden NIET opgeslagen; andere locatie/kwartaal/bestand maakt vergelijking ongeldig.
809
+ const controllerDefs=[['unique','ctrlUnique','Unieke cliënten'],['newIntake','ctrlIntake','Nieuwe instroom'],['active','ctrlActive','Actieve cliënten'],['visits','ctrlVisits','Unieke bezoekdagen']];
810
+ let controllerComparison=null;
811
+ function resetControllerComparison(clearInputs=false){
812
+ controllerComparison=null;
813
+ $('controllerBadge').textContent='NIET AANGELEVERD';
814
+ $('controllerResult').textContent='Nog geen onafhankelijke controlecijfers vergeleken.';
815
+ if(clearInputs)controllerDefs.forEach(([,id])=>{$(id).value=''});
816
+ }
817
+ function updateControllerContext(){
818
+ const r=importedData?.last;
819
+ $('controllerContext').textContent=r?`ORCHESTRA: ${r.site==='*'?'Alle locaties (som van locaties)':r.site} · ${r.period.label} · peildatum ${readableDate(r.period.peildatum)}. Gebruik precies deze selectie voor de controle.`:'Analyseer eerst het fictieve Excel-bestand en kies een locatie en kwartaal.';
820
+ }
821
+ function compareController(){
822
+ const r=importedData?.last;
823
+ if(!r){$('controllerResult').textContent='⚠ Analyseer eerst een fictief Excel-testbestand.';return}
824
+ const values={};
825
+ for(const [key,id] of controllerDefs){const el=$(id),v=el.value.trim();if(!/^\d+$/.test(v)||!Number.isSafeInteger(Number(v))){$('controllerResult').textContent='⚠ Vul alle vier de controlewaarden in als geldige, niet-negatieve gehele getallen.';el.focus();return}values[key]=Number(v)}
826
+ const rows=controllerDefs.map(([key,,label])=>({label,ours:r[key],controller:values[key],delta:r[key]-values[key]}));
827
+ const count=rows.filter(x=>x.delta!==0).length;
828
+ controllerComparison={site:r.site,period:r.period.label,rows,count};
829
+ const fmt=x=>Number(x).toLocaleString('nl-NL');
830
+ const rendered=rows.map(x=>`<tr><td>${escapeHTML(x.label)}</td><td>${fmt(x.ours)}</td><td>${fmt(x.controller)}</td><td class="${x.delta?'controller-bad':'controller-ok'}">${x.delta?(x.delta>0?'+':'')+fmt(x.delta):'✓ 0'}</td></tr>`).join('');
831
+ $('controllerResult').innerHTML=`<div class="controller-summary">${count?`⚠ ${count} van 4 indicatoren wijken af. Onderzoek de oorzaak voordat de cijfers worden gebruikt.`:'✓ Alle 4 ingevoerde controlegetallen komen overeen. Dit is nog geen formele validatie.'}</div><table class="controller-table"><thead><tr><th>Indicator</th><th>ORCHESTRA</th><th>Controle</th><th>Verschil</th></tr></thead><tbody>${rendered}</tbody></table>`;
832
+ $('controllerBadge').textContent=count?`${count} VERSCHIL(LEN)`:'4 / 4 GELIJK';
833
+ log('Fictieve businesscontrollervergelijking: '+count+' verschil(len) op 4 indicatoren; geen formele vrijgave');
834
+ }
835
+ $('controllerCompare').addEventListener('click',compareController);
836
+ $('controllerClear').addEventListener('click',()=>resetControllerComparison(true));
837
+ controllerDefs.forEach(([,id])=>$(id).addEventListener('input',()=>{if(controllerComparison)resetControllerComparison(false)}));
838
  </script></body></html>