json bindings

This commit is contained in:
2026-06-13 20:19:36 +03:00
parent d623ee797c
commit 9eb257d237
10 changed files with 1024 additions and 24 deletions
+318
View File
@@ -0,0 +1,318 @@
<?php
include('include/headscript.php');
// Binding preparati da import_insert.php (da risolvere + collegati in automatico).
$pending = $_SESSION['pending_bindings'] ?? null;
if (empty($pending) || (empty($pending['items']) && empty($pending['auto']) && empty($pending['saved']))) {
// Niente da mostrare: vado alla griglia.
$tid = $pending['template_id'] ?? ($_SESSION['template_id'] ?? null);
$ref = $pending['importref'] ?? '';
unset($_SESSION['pending_bindings']);
if ($tid) {
header("Location: imported.php?id=" . urlencode($tid) . "&importref=" . urlencode($ref));
} else {
header("Location: xlstemplates_grid.php");
}
exit;
}
$templateId = (int) $pending['template_id'];
$importRef = (string) $pending['importref'];
$items = $pending['items'] ?? [];
$autoItems = $pending['auto'] ?? [];
$savedItems = $pending['saved'] ?? [];
// Righe gia' risolte (modificabili): auto-collegate + binding gia' salvati.
$resolvedItems = [];
foreach ($autoItems as $a) {
$a['badge'] = 'auto';
$a['badge_class'] = 'bg-success';
$resolvedItems[] = $a;
}
foreach ($savedItems as $s) {
$s['badge'] = 'salvato';
$s['badge_class'] = 'bg-secondary';
$resolvedItems[] = $s;
}
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
$stmt = $pdo->prepare("SELECT name FROM excel_templates WHERE id = ?");
$stmt->execute([$templateId]);
$templateName = $stmt->fetchColumn() ?: ('Template ' . $templateId);
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
<?php include('cssinclude.php'); ?>
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet">
<style>
.json-value {
font-family: Consolas, Monaco, monospace;
font-weight: 600;
}
.binding-status {
font-size: 12px;
}
td .select2-container {
min-width: 240px;
}
/* Allinea l'altezza di select2 a form-select/btn di Bootstrap */
.select2-container--default .select2-selection--single {
height: 38px;
border-color: #ced4da;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: 36px;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: 36px;
}
</style>
<title>Binding JSON -> LIMS - <?= htmlspecialchars($titlewebsite ?? '', ENT_QUOTES, 'UTF-8'); ?></title>
</head>
<body>
<div class="wrapper">
<?php include('include/navbar.php'); ?>
<?php include('include/topbar.php'); ?>
<div class="page-wrapper">
<div class="page-content">
<div class="card radius-10">
<div class="card-header">
<div class="d-flex align-items-center justify-content-between flex-wrap gap-2">
<div>
<h6 class="mb-0">Binding JSON -> LIMS</h6>
<small><?= htmlspecialchars($templateName) ?> - Template ID: <?= $templateId ?></small>
</div>
<a href="bindings_manage.php?template_id=<?= $templateId ?>" class="btn btn-sm btn-outline-secondary">
<i class="fas fa-cog"></i> Gestione binding
</a>
</div>
</div>
<div class="card-body">
<?php if (!empty($items)): ?>
<div class="alert alert-info">
Alcuni valori importati dal JSON non hanno ancora una corrispondenza con i valori del LIMS.
Seleziona il valore LIMS corretto per ciascuno e conferma. I binding verranno salvati e
riutilizzati nelle importazioni successive.
</div>
<?php endif; ?>
<?php if (!empty($autoItems)): ?>
<div class="alert alert-success">
<?= count($autoItems) ?> valore/i collegato/i automaticamente (corrispondenza esatta con il LIMS).
</div>
<?php endif; ?>
<div id="bindingError" class="alert alert-danger" style="display:none;"></div>
<form id="bindingForm">
<div class="table-responsive">
<table class="table table-bordered align-middle">
<thead>
<tr>
<th>Campo (template_mapping)</th>
<th>Valore JSON</th>
<th>Valore LIMS</th>
<th style="width:210px;">Azioni</th>
</tr>
</thead>
<tbody>
<?php foreach ($items as $idx => $item): ?>
<tr class="binding-row"
data-index="<?= $idx ?>"
data-mapping-id="<?= (int) $item['mapping_id'] ?>"
data-field-id="<?= (int) $item['field_id'] ?>"
data-json-value="<?= htmlspecialchars($item['json_value'], ENT_QUOTES) ?>"
data-datadb-ids="<?= htmlspecialchars(json_encode($item['datadb_ids']), ENT_QUOTES) ?>">
<td class="text-muted"><?= htmlspecialchars($item['field_label']) ?></td>
<td class="json-value"><?= htmlspecialchars($item['json_value']) ?></td>
<td>
<select class="form-select binding-select" data-field-id="<?= (int) $item['field_id'] ?>">
<option value="">Seleziona valore LIMS...</option>
</select>
</td>
<td>
<button type="button" class="btn btn-sm btn-outline-secondary skip-binding-btn">Nessuna corrispondenza</button>
<div class="binding-status text-muted mt-1">In attesa</div>
</td>
</tr>
<?php endforeach; ?>
<?php foreach ($resolvedItems as $res): ?>
<tr class="binding-row"
data-mapping-id="<?= (int) $res['mapping_id'] ?>"
data-field-id="<?= (int) $res['field_id'] ?>"
data-json-value="<?= htmlspecialchars($res['json_value'], ENT_QUOTES) ?>"
data-datadb-ids="<?= htmlspecialchars(json_encode($res['datadb_ids']), ENT_QUOTES) ?>">
<td class="text-muted"><?= htmlspecialchars($res['field_label']) ?></td>
<td class="json-value"><?= htmlspecialchars($res['json_value']) ?></td>
<td>
<select class="form-select binding-select" data-field-id="<?= (int) $res['field_id'] ?>">
<option value="<?= (int) $res['lims_value_id'] ?>" selected><?= htmlspecialchars($res['lims_value']) ?></option>
</select>
</td>
<td>
<button type="button" class="btn btn-sm btn-outline-secondary skip-binding-btn">Nessuna corrispondenza</button>
<div class="binding-status mt-1"><span class="badge <?= $res['badge_class'] ?>"><?= $res['badge'] ?></span></div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="d-flex justify-content-end gap-2 mt-3">
<a href="imported.php?id=<?= $templateId ?>&importref=<?= urlencode($importRef) ?>"
class="btn btn-outline-secondary">Salta per ora</a>
<button type="submit" class="btn btn-primary" id="confirmBindingsBtn" disabled>
Conferma e prosegui
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="overlay toggle-icon"></div>
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
<?php include('include/footer.php'); ?>
</div>
<?php include('jsinclude.php'); ?>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(function() {
const TEMPLATE_ID = <?= $templateId ?>;
const IMPORT_REF = <?= json_encode($importRef) ?>;
const CONTINUE_URL = 'imported.php?id=' + TEMPLATE_ID + '&importref=' + encodeURIComponent(IMPORT_REF);
const $form = $('#bindingForm');
const $btn = $('#confirmBindingsBtn');
const $error = $('#bindingError');
// Dropdown valori LIMS per riga (search_customfield_values.php).
$('.binding-select').each(function() {
const fieldId = $(this).data('field-id');
$(this).select2({
placeholder: 'Seleziona valore LIMS...',
width: '100%',
ajax: {
url: 'search_customfield_values.php',
dataType: 'json',
delay: 200,
data: params => ({
field_id: fieldId,
q: params.term || '',
limit: 50
}),
processResults: data => ({
results: data.results || []
})
},
minimumInputLength: 0
});
});
// Una riga e' pronta se ha un valore scelto oppure e' marcata "nessuna corrispondenza".
function refreshButton() {
const allReady = $('.binding-row').toArray().every(row => {
const $row = $(row);
return $row.hasClass('is-skipped') || $row.find('.binding-select').val();
});
$btn.prop('disabled', !allReady);
}
$('.binding-select').on('change', refreshButton);
refreshButton();
// "Nessuna corrispondenza": azzera il valore importato, nessun binding salvato.
$('.skip-binding-btn').on('click', function() {
const $row = $(this).closest('.binding-row');
const $select = $row.find('.binding-select');
const $status = $row.find('.binding-status');
const skipped = $row.toggleClass('is-skipped').hasClass('is-skipped');
$(this).toggleClass('btn-outline-secondary', !skipped).toggleClass('btn-secondary', skipped);
$select.val(null).trigger('change').prop('disabled', skipped);
$status.text(skipped ? 'Nessuna corrispondenza' : 'In attesa');
refreshButton();
});
$form.on('submit', function(e) {
e.preventDefault();
$error.hide();
$btn.prop('disabled', true).text('Salvataggio...');
const tasks = $('.binding-row').toArray().map(row => {
const $row = $(row);
const $status = $row.find('.binding-status');
const datadbIds = JSON.stringify($row.data('datadb-ids') || []);
const jsonValue = String($row.data('json-value'));
// Riga senza corrispondenza: azzera il valore, niente binding.
if ($row.hasClass('is-skipped')) {
return $.post('skip_binding.php', {
mapping_id: $row.data('mapping-id'),
json_value: jsonValue,
datadb_ids: datadbIds
}).then(resp => {
if (resp && resp.success) {
$status.text('Azzerato').removeClass('text-muted').addClass('text-success');
return true;
}
$status.text('Errore').addClass('text-danger');
throw new Error((resp && resp.error) || 'Errore azzeramento valore');
});
}
const $select = $row.find('.binding-select');
const selectedData = $select.select2('data')[0] || {};
return $.post('save_binding.php', {
mapping_id: $row.data('mapping-id'),
field_id: $row.data('field-id'),
template_id: TEMPLATE_ID,
json_value: jsonValue,
lims_value_id: $select.val(),
lims_value: selectedData.text || '',
datadb_ids: datadbIds
}).then(resp => {
if (resp && resp.success) {
$status.text('Salvato').removeClass('text-muted').addClass('text-success');
return true;
}
$status.text('Errore').addClass('text-danger');
throw new Error((resp && resp.error) || 'Errore salvataggio binding');
});
});
Promise.all(tasks)
.then(() => {
window.location.href = CONTINUE_URL;
})
.catch(err => {
$error.text(err.message || 'Errore durante il salvataggio dei binding.').show();
$btn.prop('disabled', false).text('Conferma e prosegui');
});
});
});
</script>
</body>
</html>