added fiel tecnici tags additional 2 and fixed menu
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class AddIsStrumentoIsCicloToMatriceAttachments extends AbstractMigration
|
||||
{
|
||||
public function change(): void
|
||||
{
|
||||
$this->table('matrice_attachments')
|
||||
->addColumn('is_strumento', 'boolean', [
|
||||
'default' => false,
|
||||
'null' => false,
|
||||
'after' => 'is_disegno',
|
||||
])
|
||||
->addColumn('is_ciclo', 'boolean', [
|
||||
'default' => false,
|
||||
'null' => false,
|
||||
'after' => 'is_strumento',
|
||||
])
|
||||
->update();
|
||||
}
|
||||
}
|
||||
@@ -130,7 +130,40 @@
|
||||
});
|
||||
};
|
||||
|
||||
let wsDisegniList = [];
|
||||
// ================================================================
|
||||
// Tab allegati della matrice: disegni tecnici, strumenti, cicli
|
||||
// ================================================================
|
||||
const WS_ATT_KINDS = {
|
||||
disegni: {
|
||||
flag: "is_disegno",
|
||||
label: "Disegni tecnici",
|
||||
icon: "📐",
|
||||
itemLabel: "Disegno",
|
||||
empty:
|
||||
"Nessun disegno tecnico per questo profilo. " +
|
||||
"Si possono segnare dalla gestione matrici (graffetta → pulsante compasso).",
|
||||
},
|
||||
strumenti: {
|
||||
flag: "is_strumento",
|
||||
label: "Strumenti di lavoro",
|
||||
icon: "🔧",
|
||||
itemLabel: "Strumento",
|
||||
empty:
|
||||
"Nessuno strumento di lavoro per questo profilo. " +
|
||||
"Si possono segnare dalla gestione matrici (graffetta → pulsante chiave inglese).",
|
||||
},
|
||||
cicli: {
|
||||
flag: "is_ciclo",
|
||||
label: "Cicli di lavoro",
|
||||
icon: "🔁",
|
||||
itemLabel: "Ciclo",
|
||||
empty:
|
||||
"Nessun ciclo di lavoro per questo profilo. " +
|
||||
"Si possono segnare dalla gestione matrici (graffetta → pulsante frecce).",
|
||||
},
|
||||
};
|
||||
|
||||
let wsAttLists = { disegni: [], strumenti: [], cicli: [] };
|
||||
|
||||
function wsFileExt(name) {
|
||||
const p = String(name || "").split(".");
|
||||
@@ -141,12 +174,15 @@
|
||||
return ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext);
|
||||
}
|
||||
|
||||
function showWorksheetDisegno(index) {
|
||||
const f = wsDisegniList[index];
|
||||
function showWorksheetAttachment(kind, index) {
|
||||
const list = wsAttLists[kind] || [];
|
||||
const f = list[index];
|
||||
if (!f) return;
|
||||
|
||||
$(".ws-disegno-item").removeClass("active");
|
||||
$(`.ws-disegno-item[data-index="${index}"]`).addClass("active");
|
||||
$(`.ws-disegno-item[data-kind="${kind}"]`).removeClass("active");
|
||||
$(
|
||||
`.ws-disegno-item[data-kind="${kind}"][data-index="${index}"]`,
|
||||
).addClass("active");
|
||||
|
||||
const name = f.file_name || "";
|
||||
const path = f.file_url || f.file_path || "";
|
||||
@@ -161,7 +197,7 @@
|
||||
viewer = `<div class="h-100 d-flex justify-content-center align-items-center text-muted">Anteprima non disponibile per questo formato: usa "Apri in nuova scheda"</div>`;
|
||||
}
|
||||
|
||||
$("#wsDisegnoToolbar").html(`
|
||||
$(`#wsToolbar_${kind}`).html(`
|
||||
<div>
|
||||
<div class="fw-bold">${escapeHtml(name)}</div>
|
||||
${f.description ? `<div class="small text-muted">${escapeHtml(f.description)}</div>` : ""}
|
||||
@@ -170,18 +206,59 @@
|
||||
<i class="fa-solid fa-arrow-up-right-from-square"></i> Apri in nuova scheda
|
||||
</a>
|
||||
`);
|
||||
$("#wsDisegnoViewer").html(viewer);
|
||||
$(`#wsViewer_${kind}`).html(viewer);
|
||||
}
|
||||
|
||||
function loadWorksheetDisegni(idmatrice) {
|
||||
wsDisegniList = [];
|
||||
const $c = $("#wsDisegniContainer");
|
||||
function renderWorksheetAttachmentKind(kind) {
|
||||
const cfg = WS_ATT_KINDS[kind];
|
||||
const list = wsAttLists[kind];
|
||||
const $c = $(`#wsContainer_${kind}`);
|
||||
|
||||
$(`#wsCount_${kind}`).text(list.length);
|
||||
|
||||
if (!list.length) {
|
||||
$c.html(
|
||||
`<div class="text-muted p-3">${escapeHtml(cfg.empty)}</div>`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let listHtml = "";
|
||||
if (list.length > 1) {
|
||||
listHtml =
|
||||
'<div class="ws-disegni-list">' +
|
||||
list
|
||||
.map(
|
||||
(f, i) =>
|
||||
`<button type="button" class="ws-disegno-item" data-kind="${kind}" data-index="${i}">${cfg.icon} ${escapeHtml(f.file_name || cfg.itemLabel + " " + (i + 1))}</button>`,
|
||||
)
|
||||
.join("") +
|
||||
"</div>";
|
||||
}
|
||||
|
||||
$c.html(`
|
||||
${listHtml}
|
||||
<div class="ws-disegno-toolbar" id="wsToolbar_${kind}"></div>
|
||||
<div class="ws-disegno-viewer" id="wsViewer_${kind}"></div>
|
||||
`);
|
||||
|
||||
// Se l'utente ha già aperto il tab mentre caricava, mostro subito il primo
|
||||
if ($(`.ws-tab[data-tab="${kind}"]`).hasClass("active")) {
|
||||
showWorksheetAttachment(kind, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function loadWorksheetAttachments(idmatrice) {
|
||||
wsAttLists = { disegni: [], strumenti: [], cicli: [] };
|
||||
const kinds = Object.keys(WS_ATT_KINDS);
|
||||
|
||||
if (!idmatrice) {
|
||||
$("#wsDisegniCount").text("0");
|
||||
$c.html(
|
||||
'<div class="text-muted">Nessun profilo collegato a questo foglio.</div>',
|
||||
);
|
||||
kinds.forEach((k) => {
|
||||
$(`#wsCount_${k}`).text("0");
|
||||
$(`#wsContainer_${k}`).html(
|
||||
'<div class="text-muted">Nessun profilo collegato a questo foglio.</div>',
|
||||
);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,50 +270,25 @@
|
||||
data.message || "Errore caricamento allegati",
|
||||
);
|
||||
|
||||
wsDisegniList = (data.attachments || []).filter(
|
||||
(a) => parseInt(a.is_disegno, 10) === 1,
|
||||
);
|
||||
$("#wsDisegniCount").text(wsDisegniList.length);
|
||||
const all = data.attachments || [];
|
||||
|
||||
if (!wsDisegniList.length) {
|
||||
$c.html(
|
||||
'<div class="text-muted p-3">Nessun disegno tecnico per questo profilo. ' +
|
||||
"Si possono segnare dalla gestione matrici (graffetta → pulsante compasso).</div>",
|
||||
kinds.forEach((k) => {
|
||||
const flag = WS_ATT_KINDS[k].flag;
|
||||
wsAttLists[k] = all.filter(
|
||||
(a) => parseInt(a[flag], 10) === 1,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let listHtml = "";
|
||||
if (wsDisegniList.length > 1) {
|
||||
listHtml =
|
||||
'<div class="ws-disegni-list">' +
|
||||
wsDisegniList
|
||||
.map(
|
||||
(f, i) =>
|
||||
`<button type="button" class="ws-disegno-item" data-index="${i}">📐 ${escapeHtml(f.file_name || "Disegno " + (i + 1))}</button>`,
|
||||
)
|
||||
.join("") +
|
||||
"</div>";
|
||||
}
|
||||
|
||||
$c.html(`
|
||||
${listHtml}
|
||||
<div class="ws-disegno-toolbar" id="wsDisegnoToolbar"></div>
|
||||
<div class="ws-disegno-viewer" id="wsDisegnoViewer"></div>
|
||||
`);
|
||||
|
||||
// Se l'utente ha già aperto il tab mentre caricava, mostro subito il primo
|
||||
if ($('.ws-tab[data-tab="disegni"]').hasClass("active")) {
|
||||
showWorksheetDisegno(0);
|
||||
}
|
||||
renderWorksheetAttachmentKind(k);
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
$("#wsDisegniCount").text("!");
|
||||
$c.html(
|
||||
'<div class="text-danger">Errore nel caricamento dei disegni: ' +
|
||||
escapeHtml(err.message || "") +
|
||||
"</div>",
|
||||
);
|
||||
kinds.forEach((k) => {
|
||||
$(`#wsCount_${k}`).text("!");
|
||||
$(`#wsContainer_${k}`).html(
|
||||
'<div class="text-danger">Errore nel caricamento degli allegati: ' +
|
||||
escapeHtml(err.message || "") +
|
||||
"</div>",
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -437,6 +489,28 @@
|
||||
</div>
|
||||
`;
|
||||
|
||||
const attTabsHtml = Object.keys(WS_ATT_KINDS)
|
||||
.map((k) => {
|
||||
const c = WS_ATT_KINDS[k];
|
||||
return `
|
||||
<button type="button" class="ws-tab" data-tab="${k}">
|
||||
${c.icon} ${escapeHtml(c.label)} <span class="ws-tab-count" id="wsCount_${k}">…</span>
|
||||
</button>`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
const attPanesHtml = Object.keys(WS_ATT_KINDS)
|
||||
.map((k) => {
|
||||
const c = WS_ATT_KINDS[k];
|
||||
return `
|
||||
<div class="ws-tab-pane" data-pane="${k}">
|
||||
<div id="wsContainer_${k}">
|
||||
<div class="text-muted">Caricamento ${escapeHtml(c.label.toLowerCase())}...</div>
|
||||
</div>
|
||||
</div>`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
const fullHtml = `
|
||||
${headerHtml}
|
||||
|
||||
@@ -444,24 +518,18 @@
|
||||
<button type="button" class="ws-tab active" data-tab="dati">
|
||||
<i class="fa-solid fa-file-lines me-1"></i> Dati foglio
|
||||
</button>
|
||||
<button type="button" class="ws-tab" data-tab="disegni">
|
||||
📐 Disegni tecnici <span class="ws-tab-count" id="wsDisegniCount">…</span>
|
||||
</button>
|
||||
${attTabsHtml}
|
||||
</div>
|
||||
|
||||
<div class="ws-tab-pane active" data-pane="dati">
|
||||
${html}
|
||||
</div>
|
||||
|
||||
<div class="ws-tab-pane" data-pane="disegni">
|
||||
<div id="wsDisegniContainer">
|
||||
<div class="text-muted">Caricamento disegni tecnici...</div>
|
||||
</div>
|
||||
</div>
|
||||
${attPanesHtml}
|
||||
`;
|
||||
|
||||
$("#worksheetDetailContainer").html(fullHtml);
|
||||
loadWorksheetDisegni(ws.idmatrice);
|
||||
loadWorksheetAttachments(ws.idmatrice);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Catch loadMatriceWorksheets:", err);
|
||||
@@ -495,18 +563,21 @@
|
||||
$(".ws-tab-pane").removeClass("active");
|
||||
$(`.ws-tab-pane[data-pane="${tab}"]`).addClass("active");
|
||||
|
||||
// Carico il PDF solo la prima volta che si apre il tab
|
||||
// Carico il file solo la prima volta che si apre il tab
|
||||
if (
|
||||
tab === "disegni" &&
|
||||
wsDisegniList.length &&
|
||||
$("#wsDisegnoViewer").is(":empty")
|
||||
WS_ATT_KINDS[tab] &&
|
||||
(wsAttLists[tab] || []).length &&
|
||||
$(`#wsViewer_${tab}`).is(":empty")
|
||||
) {
|
||||
showWorksheetDisegno(0);
|
||||
showWorksheetAttachment(tab, 0);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("click", ".ws-disegno-item", function () {
|
||||
showWorksheetDisegno(parseInt($(this).data("index"), 10));
|
||||
showWorksheetAttachment(
|
||||
$(this).data("kind"),
|
||||
parseInt($(this).data("index"), 10),
|
||||
);
|
||||
});
|
||||
|
||||
$(document).on("click", ".open-worksheet-detail", function () {
|
||||
|
||||
@@ -28,6 +28,8 @@ try {
|
||||
description,
|
||||
sort_order,
|
||||
is_disegno,
|
||||
is_strumento,
|
||||
is_ciclo,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM matrice_attachments
|
||||
@@ -52,6 +54,8 @@ try {
|
||||
'description' => $row['description'] ?? '',
|
||||
'sort_order' => (int)($row['sort_order'] ?? 0),
|
||||
'is_disegno' => (int)($row['is_disegno'] ?? 0),
|
||||
'is_strumento' => (int)($row['is_strumento'] ?? 0),
|
||||
'is_ciclo' => (int)($row['is_ciclo'] ?? 0),
|
||||
'created_at' => !empty($row['created_at']) ? date('d/m/Y H:i', strtotime($row['created_at'])) : '',
|
||||
'updated_at' => !empty($row['updated_at']) ? date('d/m/Y H:i', strtotime($row['updated_at'])) : ''
|
||||
];
|
||||
|
||||
@@ -27,6 +27,14 @@
|
||||
background: #6f42c1;
|
||||
}
|
||||
|
||||
.ws-tab[data-tab="strumenti"].active {
|
||||
background: #fd7e14;
|
||||
}
|
||||
|
||||
.ws-tab[data-tab="cicli"].active {
|
||||
background: #0f9d77;
|
||||
}
|
||||
|
||||
.ws-tab-count {
|
||||
display: inline-block;
|
||||
min-width: 24px;
|
||||
@@ -67,6 +75,26 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ws-disegno-item[data-kind="strumenti"] {
|
||||
border-color: #fd7e14;
|
||||
color: #fd7e14;
|
||||
}
|
||||
|
||||
.ws-disegno-item[data-kind="strumenti"].active {
|
||||
background: #fd7e14;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ws-disegno-item[data-kind="cicli"] {
|
||||
border-color: #0f9d77;
|
||||
color: #0f9d77;
|
||||
}
|
||||
|
||||
.ws-disegno-item[data-kind="cicli"].active {
|
||||
background: #0f9d77;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ws-disegno-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
+131
-6
@@ -577,6 +577,60 @@ function revisionLabel($rev)
|
||||
background: #6f42c1;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.attachments-existing-list .attachment-existing-row.is-ciclo:not(.is-disegno) {
|
||||
border: 2px solid #0f9d77;
|
||||
background: #effaf6;
|
||||
}
|
||||
|
||||
.attachments-existing-list .attachment-existing-row.is-strumento:not(.is-disegno):not(.is-ciclo) {
|
||||
border: 2px solid #fd7e14;
|
||||
background: #fff6ee;
|
||||
}
|
||||
|
||||
.badge-strumento,
|
||||
.badge-ciclo {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
color: #fff;
|
||||
font-size: .78rem;
|
||||
font-weight: 700;
|
||||
padding: 4px 9px;
|
||||
border-radius: 999px;
|
||||
margin-left: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.badge-strumento {
|
||||
background: #fd7e14;
|
||||
}
|
||||
|
||||
.badge-ciclo {
|
||||
background: #0f9d77;
|
||||
}
|
||||
|
||||
.btn-toggle-strumento {
|
||||
border-color: #fd7e14;
|
||||
color: #fd7e14;
|
||||
}
|
||||
|
||||
.btn-toggle-strumento:hover,
|
||||
.btn-toggle-strumento.active {
|
||||
background: #fd7e14;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-toggle-ciclo {
|
||||
border-color: #0f9d77;
|
||||
color: #0f9d77;
|
||||
}
|
||||
|
||||
.btn-toggle-ciclo:hover,
|
||||
.btn-toggle-ciclo.active {
|
||||
background: #0f9d77;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@@ -1175,9 +1229,11 @@ function revisionLabel($rev)
|
||||
return;
|
||||
}
|
||||
|
||||
const list = (data.attachments || []).sort((a, b) =>
|
||||
(parseInt(b.is_disegno, 10) || 0) - (parseInt(a.is_disegno, 10) || 0)
|
||||
);
|
||||
const flagScore = x =>
|
||||
(parseInt(x.is_disegno, 10) || 0) * 4 +
|
||||
(parseInt(x.is_ciclo, 10) || 0) * 2 +
|
||||
(parseInt(x.is_strumento, 10) || 0);
|
||||
const list = (data.attachments || []).sort((a, b) => flagScore(b) - flagScore(a));
|
||||
const container = $("#existingAttachmentsList");
|
||||
container.empty();
|
||||
|
||||
@@ -1196,6 +1252,8 @@ function revisionLabel($rev)
|
||||
const createdAt = item.created_at || '';
|
||||
const id = item.id || 0;
|
||||
const isDisegno = (parseInt(item.is_disegno, 10) || 0) === 1;
|
||||
const isStrumento = (parseInt(item.is_strumento, 10) || 0) === 1;
|
||||
const isCiclo = (parseInt(item.is_ciclo, 10) || 0) === 1;
|
||||
|
||||
const previewHtml = isImageExt(ext) && filePath ?
|
||||
`<img src="${escapeHtml(filePath)}" class="attachment-preview-thumb" alt="">` :
|
||||
@@ -1221,7 +1279,7 @@ function revisionLabel($rev)
|
||||
}
|
||||
|
||||
const html = `
|
||||
<div class="attachment-existing-row ${isDisegno ? 'is-disegno' : ''}">
|
||||
<div class="attachment-existing-row ${isDisegno ? 'is-disegno' : ''} ${isCiclo ? 'is-ciclo' : ''} ${isStrumento ? 'is-strumento' : ''}">
|
||||
<div class="d-flex gap-3 align-items-start">
|
||||
<div>${previewHtml}</div>
|
||||
|
||||
@@ -1230,7 +1288,9 @@ function revisionLabel($rev)
|
||||
<div>
|
||||
<div class="attachment-meta-title">
|
||||
${escapeHtml(fileName)}
|
||||
${isDisegno ? '<span class="badge-disegno"><i class="fa-solid fa-compass-drafting"></i> Disegno tecnico</span>' : ''}
|
||||
${isDisegno ? '<span class="badge-disegno"><i class="fa-solid fa-compass-drafting"></i> Disegno tecnico</span>' : ''}
|
||||
${isStrumento ? '<span class="badge-strumento"><i class="fa-solid fa-screwdriver-wrench"></i> Strumento di lavoro</span>' : ''}
|
||||
${isCiclo ? '<span class="badge-ciclo"><i class="fa-solid fa-arrows-rotate"></i> Ciclo di lavoro</span>' : ''}
|
||||
</div>
|
||||
<div class="attachment-meta-sub">${badge} ${createdAt ? ' • ' + escapeHtml(createdAt) : ''}</div>
|
||||
</div>
|
||||
@@ -1241,9 +1301,25 @@ function revisionLabel($rev)
|
||||
class="btn btn-sm btn-toggle-disegno toggle-disegno ${isDisegno ? 'active' : ''}"
|
||||
data-id="${id}"
|
||||
data-value="${isDisegno ? 1 : 0}"
|
||||
title="${isDisegno ? 'Togli da disegni tecnici' : 'Segna come disegno tecnico'}">
|
||||
title="${isDisegno ? 'Togli da disegni tecnici' : 'Segna come disegno tecnico'}">
|
||||
<i class="fa-solid fa-compass-drafting"></i>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-toggle-strumento toggle-flag ${isStrumento ? 'active' : ''}"
|
||||
data-id="${id}"
|
||||
data-field="is_strumento"
|
||||
data-value="${isStrumento ? 1 : 0}"
|
||||
title="${isStrumento ? 'Togli da strumenti di lavoro' : 'Segna come strumento di lavoro'}">
|
||||
<i class="fa-solid fa-screwdriver-wrench"></i>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-toggle-ciclo toggle-flag ${isCiclo ? 'active' : ''}"
|
||||
data-id="${id}"
|
||||
data-field="is_ciclo"
|
||||
data-value="${isCiclo ? 1 : 0}"
|
||||
title="${isCiclo ? 'Togli da cicli di lavoro' : 'Segna come ciclo di lavoro'}">
|
||||
<i class="fa-solid fa-arrows-rotate"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger delete-existing-file" data-id="${id}">Elimina</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1820,6 +1896,55 @@ function revisionLabel($rev)
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on("click", ".toggle-flag", function() {
|
||||
const $btn = $(this);
|
||||
const id = $btn.data("id");
|
||||
const field = $btn.data("field");
|
||||
const newValue = parseInt($btn.data("value"), 10) === 1 ? 0 : 1;
|
||||
const idmatrice = $("#mf_idmatrice").val();
|
||||
|
||||
$btn.prop("disabled", true);
|
||||
|
||||
fetch("toggle_matrice_attachment_disegno.php", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
body: "id=" + encodeURIComponent(id) +
|
||||
"&field=" + encodeURIComponent(field) +
|
||||
"&value=" + newValue
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.success) {
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Errore",
|
||||
text: data.message || ""
|
||||
});
|
||||
$btn.prop("disabled", false);
|
||||
return;
|
||||
}
|
||||
Swal.fire({
|
||||
toast: true,
|
||||
position: "top-end",
|
||||
icon: "success",
|
||||
title: data.message,
|
||||
showConfirmButton: false,
|
||||
timer: 1500
|
||||
});
|
||||
loadExistingAttachments(idmatrice);
|
||||
})
|
||||
.catch(() => {
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Errore",
|
||||
text: "Errore di comunicazione con il server"
|
||||
});
|
||||
$btn.prop("disabled", false);
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on("click", ".preview-existing-file", function() {
|
||||
const file = $(this).data("file") || "";
|
||||
const name = $(this).data("name") || "Anteprima file";
|
||||
|
||||
@@ -241,7 +241,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include('jsinclude.php'); ?>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include('jsinclude.php'); ?>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
<!-- jQuery, Bootstrap, DataTables, SweetAlert -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
|
||||
<link rel="stylesheet"
|
||||
@@ -76,6 +75,68 @@
|
||||
font-weight: 600;
|
||||
padding: 10px 18px;
|
||||
}
|
||||
|
||||
/* Tabella attrezzature: colonne fisse, testo a capo, ridimensionabili */
|
||||
#tabTools {
|
||||
width: 100% !important;
|
||||
table-layout: fixed;
|
||||
font-size: .95rem;
|
||||
}
|
||||
|
||||
#tabTools td {
|
||||
white-space: normal !important;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
/* Titoli: a capo solo tra le parole, mai a metà */
|
||||
#tabTools th {
|
||||
position: relative;
|
||||
white-space: normal !important;
|
||||
word-break: normal;
|
||||
overflow-wrap: normal;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
/* Maniglia per ridimensionare */
|
||||
.col-resizer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 7px;
|
||||
height: 100%;
|
||||
cursor: col-resize;
|
||||
user-select: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.col-resizer:hover,
|
||||
.col-resizer.resizing {
|
||||
background: rgba(13, 110, 253, .35);
|
||||
}
|
||||
|
||||
/* Lineetta sempre visibile tra i titoli */
|
||||
.col-resizer::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 20%;
|
||||
bottom: 20%;
|
||||
right: 3px;
|
||||
width: 2px;
|
||||
border-radius: 2px;
|
||||
background: #cbd5e1;
|
||||
}
|
||||
|
||||
.col-resizer:hover::after,
|
||||
.col-resizer.resizing::after {
|
||||
background: #0d6efd;
|
||||
}
|
||||
|
||||
body.col-resizing {
|
||||
cursor: col-resize;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@@ -298,11 +359,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include('jsinclude.php'); ?>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
$('#tabTools').DataTable({
|
||||
autoWidth: false,
|
||||
initComplete: function() {
|
||||
initColResize();
|
||||
},
|
||||
order: [
|
||||
[0, 'asc']
|
||||
],
|
||||
@@ -312,6 +377,104 @@
|
||||
}
|
||||
});
|
||||
|
||||
// ↔️ COLONNE RIDIMENSIONABILI (salvate nel browser, doppio clic = ripristina)
|
||||
function initColResize() {
|
||||
const table = document.getElementById("tabTools");
|
||||
const ths = Array.from(table.querySelectorAll("thead th"));
|
||||
const KEY = "tabTools_colWidths_v2";
|
||||
const MIN = 50;
|
||||
let justResized = false;
|
||||
|
||||
// Nome, N.Reg, N.Seriale, Tipo, Produttore, Descrizione, Stato, Azioni (totale 100)
|
||||
const DEFAULT = [30, 10, 10, 10, 10, 16, 8, 6];
|
||||
|
||||
function applyPct(pcts) {
|
||||
ths.forEach((th, i) => th.style.width = pcts[i] + "%");
|
||||
}
|
||||
|
||||
applyPct(DEFAULT);
|
||||
|
||||
try {
|
||||
const saved = JSON.parse(localStorage.getItem(KEY) || "null");
|
||||
if (Array.isArray(saved) && saved.length === ths.length) applyPct(saved);
|
||||
} catch (e) {}
|
||||
|
||||
function savePct() {
|
||||
const total = ths.reduce((s, th) => s + th.offsetWidth, 0);
|
||||
const pcts = ths.map(th => +(th.offsetWidth / total * 100).toFixed(2));
|
||||
applyPct(pcts);
|
||||
try {
|
||||
localStorage.setItem(KEY, JSON.stringify(pcts));
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Evita che il rilascio del mouse dopo il trascinamento faccia ordinare la colonna
|
||||
table.querySelector("thead").addEventListener("click", function(e) {
|
||||
if (justResized) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
justResized = false;
|
||||
}
|
||||
}, true);
|
||||
|
||||
ths.forEach((th, i) => {
|
||||
if (i === ths.length - 1) return; // l'ultima colonna non ha maniglia
|
||||
|
||||
const handle = document.createElement("div");
|
||||
handle.className = "col-resizer";
|
||||
handle.title = "Trascina per allargare · doppio clic per ripristinare";
|
||||
th.appendChild(handle);
|
||||
|
||||
handle.addEventListener("click", e => e.stopPropagation());
|
||||
|
||||
handle.addEventListener("dblclick", e => {
|
||||
e.stopPropagation();
|
||||
try {
|
||||
localStorage.removeItem(KEY);
|
||||
} catch (err) {}
|
||||
applyPct(DEFAULT);
|
||||
});
|
||||
|
||||
handle.addEventListener("mousedown", e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const next = ths[i + 1];
|
||||
const widths = ths.map(t => t.offsetWidth);
|
||||
ths.forEach((t, j) => t.style.width = widths[j] + "px");
|
||||
|
||||
const startX = e.pageX;
|
||||
const startW = widths[i];
|
||||
const startN = widths[i + 1];
|
||||
|
||||
handle.classList.add("resizing");
|
||||
document.body.classList.add("col-resizing");
|
||||
|
||||
function onMove(ev) {
|
||||
let d = ev.pageX - startX;
|
||||
d = Math.max(MIN - startW, Math.min(startN - MIN, d));
|
||||
th.style.width = (startW + d) + "px";
|
||||
next.style.width = (startN - d) + "px";
|
||||
}
|
||||
|
||||
function onUp() {
|
||||
document.removeEventListener("mousemove", onMove);
|
||||
document.removeEventListener("mouseup", onUp);
|
||||
handle.classList.remove("resizing");
|
||||
document.body.classList.remove("col-resizing");
|
||||
justResized = true;
|
||||
setTimeout(() => {
|
||||
justResized = false;
|
||||
}, 0);
|
||||
savePct();
|
||||
}
|
||||
|
||||
document.addEventListener("mousemove", onMove);
|
||||
document.addEventListener("mouseup", onUp);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ➕ ADD TOOL
|
||||
$("#addToolForm").on("submit", function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -13,17 +13,30 @@ function jsonOut($success, $message = '')
|
||||
exit;
|
||||
}
|
||||
|
||||
// Campi ammessi => [messaggio attivato, messaggio disattivato]
|
||||
$campi = [
|
||||
'is_disegno' => ['Segnato come disegno tecnico', 'Rimosso dai disegni tecnici'],
|
||||
'is_strumento' => ['Segnato come strumento di lavoro', 'Rimosso dagli strumenti di lavoro'],
|
||||
'is_ciclo' => ['Segnato come ciclo di lavoro', 'Rimosso dai cicli di lavoro'],
|
||||
];
|
||||
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
$value = ($_POST['is_disegno'] ?? '0') === '1' ? 1 : 0;
|
||||
$field = (string)($_POST['field'] ?? 'is_disegno');
|
||||
$raw = $_POST['value'] ?? ($_POST['is_disegno'] ?? '0');
|
||||
$value = ((string)$raw === '1') ? 1 : 0;
|
||||
|
||||
if ($id <= 0) {
|
||||
jsonOut(false, 'ID allegato non valido');
|
||||
}
|
||||
|
||||
if (!isset($campi[$field])) {
|
||||
jsonOut(false, 'Categoria non valida');
|
||||
}
|
||||
|
||||
try {
|
||||
$st = $pdo->prepare("UPDATE matrice_attachments SET is_disegno = ? WHERE id = ?");
|
||||
$st = $pdo->prepare("UPDATE matrice_attachments SET `$field` = ? WHERE id = ?");
|
||||
$st->execute([$value, $id]);
|
||||
jsonOut(true, $value ? 'Segnato come disegno tecnico' : 'Rimosso dai disegni tecnici');
|
||||
jsonOut(true, $value ? $campi[$field][0] : $campi[$field][1]);
|
||||
} catch (Throwable $e) {
|
||||
jsonOut(false, 'Errore: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user