This commit is contained in:
@ -1,6 +1,7 @@
|
||||
import { apiGet } from '../api.js';
|
||||
import { homeNavButton, showToast } from '../app.js';
|
||||
import { buildResultColumns, resultColumnCellValue } from '../test-data.js';
|
||||
import { formatBerlinDateTimeShort } from '../datetime.js';
|
||||
|
||||
const PAGE_SIZE = 50;
|
||||
|
||||
@ -9,6 +10,7 @@ let sortDir = 'asc';
|
||||
let allClients = [];
|
||||
let questionsDef = [];
|
||||
let resultColumns = [];
|
||||
let scoringProfileCatalog = [];
|
||||
let questionnaireMeta = null;
|
||||
let filterCoach = '';
|
||||
let filterSupervisor = '';
|
||||
@ -52,6 +54,7 @@ export async function resultsPage(params) {
|
||||
const data = await apiGet(`results.php?questionnaireID=${encodeURIComponent(params.id)}`);
|
||||
questionnaireMeta = data.questionnaire;
|
||||
questionsDef = data.questions || [];
|
||||
scoringProfileCatalog = data.scoringProfiles || [];
|
||||
allClients = data.clients || [];
|
||||
document.getElementById('resultsTitle').textContent = `Results: ${questionnaireMeta.name} v${questionnaireMeta.version}`;
|
||||
renderResults();
|
||||
@ -181,6 +184,40 @@ function renderResults() {
|
||||
renderTableRows();
|
||||
}
|
||||
|
||||
function scoringTableColumns() {
|
||||
const cols = [];
|
||||
for (const profile of scoringProfileCatalog) {
|
||||
const name = profile.name || profile.profileID;
|
||||
cols.push(
|
||||
{ key: `score_${profile.profileID}_calc`, label: `${name} calculated`, profileID: profile.profileID, field: 'calculated', title: `${name} — server-calculated category` },
|
||||
{ key: `score_${profile.profileID}_coach`, label: `${name} counselor`, profileID: profile.profileID, field: 'counselor', title: `${name} — counselor category` },
|
||||
{ key: `score_${profile.profileID}_by`, label: `${name} override by`, profileID: profile.profileID, field: 'override_by', title: `${name} — who overrode the calculated category` },
|
||||
{ key: `score_${profile.profileID}_at`, label: `${name} override at`, profileID: profile.profileID, field: 'override_at', title: `${name} — when the override was set` },
|
||||
);
|
||||
}
|
||||
return cols;
|
||||
}
|
||||
|
||||
function scoringCellValue(client, profileID, field) {
|
||||
const p = (client.scoringProfiles || []).find(x => x.profileID === profileID);
|
||||
if (!p) return '';
|
||||
const calc = p.calculatedBand || p.band || '';
|
||||
const coach = p.coachBand || '';
|
||||
const differs = Boolean(p.coachOverride) || (coach && coach !== calc);
|
||||
switch (field) {
|
||||
case 'calculated':
|
||||
return calc;
|
||||
case 'counselor':
|
||||
return coach;
|
||||
case 'override_by':
|
||||
return differs ? (p.coachReviewedByUsername || '') : '';
|
||||
case 'override_at':
|
||||
return differs ? (p.coachReviewedAt || '') : '';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function renderTableHead() {
|
||||
const head = document.getElementById('resultsHead');
|
||||
const fixedCols = [
|
||||
@ -191,7 +228,8 @@ function renderTableHead() {
|
||||
{ key: 'sumPoints', label: 'Score' },
|
||||
{ key: 'completedAt', label: 'Completed' },
|
||||
];
|
||||
const allCols = [...fixedCols, ...resultColumns.map(col => ({
|
||||
const scoringCols = scoringTableColumns();
|
||||
const allCols = [...fixedCols, ...scoringCols, ...resultColumns.map(col => ({
|
||||
key: col.key,
|
||||
label: col.label,
|
||||
title: col.title,
|
||||
@ -381,6 +419,11 @@ function renderTableRows() {
|
||||
return `<td>${esc(String(val))}</td>`;
|
||||
}).join('');
|
||||
|
||||
const scoringCells = scoringTableColumns().map(col => {
|
||||
const val = scoringCellValue(c, col.profileID, col.field);
|
||||
return `<td>${val ? esc(String(val)) : '—'}</td>`;
|
||||
}).join('');
|
||||
|
||||
return `<tr>
|
||||
<td class="sticky-col">${esc(c.clientCode)}</td>
|
||||
<td>${esc(coachDisplayName(c))}</td>
|
||||
@ -388,6 +431,7 @@ function renderTableRows() {
|
||||
<td>${statusBadge}</td>
|
||||
<td>${c.sumPoints !== null ? c.sumPoints : '—'}</td>
|
||||
<td>${completedDate}</td>
|
||||
${scoringCells}
|
||||
${questionCells}
|
||||
</tr>`;
|
||||
}).join('');
|
||||
@ -400,6 +444,10 @@ function getCellValue(client, key) {
|
||||
if (key === 'status') return client.status;
|
||||
if (key === 'sumPoints') return client.sumPoints;
|
||||
if (key === 'completedAt') return client.completedAt;
|
||||
const scoringCol = scoringTableColumns().find(c => c.key === key);
|
||||
if (scoringCol) {
|
||||
return scoringCellValue(client, scoringCol.profileID, scoringCol.field);
|
||||
}
|
||||
const col = resultColumns.find(c => c.key === key);
|
||||
if (col) {
|
||||
const ans = client.answers && client.answers[col.questionID];
|
||||
@ -424,19 +472,23 @@ function exportCSV() {
|
||||
});
|
||||
|
||||
const headers = ['clientCode', 'Counselor', 'supervisor', 'status', 'sumPoints', 'completedAt',
|
||||
...scoringTableColumns().map(col => col.label),
|
||||
...resultColumns.map(col => col.label)];
|
||||
|
||||
const rows = clients.map(c => {
|
||||
const base = [
|
||||
c.clientCode, coachDisplayName(c), c.supervisorUsername || '', c.status, c.sumPoints ?? '',
|
||||
c.completedAt ? new Date(c.completedAt * 1000).toISOString() : ''
|
||||
c.completedAt ? formatBerlinDateTimeShort(c.completedAt * 1000) : ''
|
||||
];
|
||||
const scoringCols = scoringTableColumns().map(col =>
|
||||
scoringCellValue(c, col.profileID, col.field)
|
||||
);
|
||||
const answerCols = resultColumns.map(col => {
|
||||
const ans = c.answers && c.answers[col.questionID];
|
||||
const val = resultColumnCellValue(col, ans, optionMap);
|
||||
return val != null ? val : '';
|
||||
});
|
||||
return [...base, ...answerCols];
|
||||
return [...base, ...scoringCols, ...answerCols];
|
||||
});
|
||||
|
||||
let csv = '\uFEFF'; // BOM
|
||||
|
||||
Reference in New Issue
Block a user