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) {
|
function wsFileExt(name) {
|
||||||
const p = String(name || "").split(".");
|
const p = String(name || "").split(".");
|
||||||
@@ -141,12 +174,15 @@
|
|||||||
return ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext);
|
return ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showWorksheetDisegno(index) {
|
function showWorksheetAttachment(kind, index) {
|
||||||
const f = wsDisegniList[index];
|
const list = wsAttLists[kind] || [];
|
||||||
|
const f = list[index];
|
||||||
if (!f) return;
|
if (!f) return;
|
||||||
|
|
||||||
$(".ws-disegno-item").removeClass("active");
|
$(`.ws-disegno-item[data-kind="${kind}"]`).removeClass("active");
|
||||||
$(`.ws-disegno-item[data-index="${index}"]`).addClass("active");
|
$(
|
||||||
|
`.ws-disegno-item[data-kind="${kind}"][data-index="${index}"]`,
|
||||||
|
).addClass("active");
|
||||||
|
|
||||||
const name = f.file_name || "";
|
const name = f.file_name || "";
|
||||||
const path = f.file_url || f.file_path || "";
|
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>`;
|
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>
|
||||||
<div class="fw-bold">${escapeHtml(name)}</div>
|
<div class="fw-bold">${escapeHtml(name)}</div>
|
||||||
${f.description ? `<div class="small text-muted">${escapeHtml(f.description)}</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
|
<i class="fa-solid fa-arrow-up-right-from-square"></i> Apri in nuova scheda
|
||||||
</a>
|
</a>
|
||||||
`);
|
`);
|
||||||
$("#wsDisegnoViewer").html(viewer);
|
$(`#wsViewer_${kind}`).html(viewer);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadWorksheetDisegni(idmatrice) {
|
function renderWorksheetAttachmentKind(kind) {
|
||||||
wsDisegniList = [];
|
const cfg = WS_ATT_KINDS[kind];
|
||||||
const $c = $("#wsDisegniContainer");
|
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) {
|
if (!idmatrice) {
|
||||||
$("#wsDisegniCount").text("0");
|
kinds.forEach((k) => {
|
||||||
$c.html(
|
$(`#wsCount_${k}`).text("0");
|
||||||
|
$(`#wsContainer_${k}`).html(
|
||||||
'<div class="text-muted">Nessun profilo collegato a questo foglio.</div>',
|
'<div class="text-muted">Nessun profilo collegato a questo foglio.</div>',
|
||||||
);
|
);
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,51 +270,26 @@
|
|||||||
data.message || "Errore caricamento allegati",
|
data.message || "Errore caricamento allegati",
|
||||||
);
|
);
|
||||||
|
|
||||||
wsDisegniList = (data.attachments || []).filter(
|
const all = data.attachments || [];
|
||||||
(a) => parseInt(a.is_disegno, 10) === 1,
|
|
||||||
|
kinds.forEach((k) => {
|
||||||
|
const flag = WS_ATT_KINDS[k].flag;
|
||||||
|
wsAttLists[k] = all.filter(
|
||||||
|
(a) => parseInt(a[flag], 10) === 1,
|
||||||
);
|
);
|
||||||
$("#wsDisegniCount").text(wsDisegniList.length);
|
renderWorksheetAttachmentKind(k);
|
||||||
|
});
|
||||||
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>",
|
|
||||||
);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
$("#wsDisegniCount").text("!");
|
kinds.forEach((k) => {
|
||||||
$c.html(
|
$(`#wsCount_${k}`).text("!");
|
||||||
'<div class="text-danger">Errore nel caricamento dei disegni: ' +
|
$(`#wsContainer_${k}`).html(
|
||||||
|
'<div class="text-danger">Errore nel caricamento degli allegati: ' +
|
||||||
escapeHtml(err.message || "") +
|
escapeHtml(err.message || "") +
|
||||||
"</div>",
|
"</div>",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.loadWorksheetDetail = function (worksheetId, endpoint) {
|
window.loadWorksheetDetail = function (worksheetId, endpoint) {
|
||||||
@@ -437,6 +489,28 @@
|
|||||||
</div>
|
</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 = `
|
const fullHtml = `
|
||||||
${headerHtml}
|
${headerHtml}
|
||||||
|
|
||||||
@@ -444,24 +518,18 @@
|
|||||||
<button type="button" class="ws-tab active" data-tab="dati">
|
<button type="button" class="ws-tab active" data-tab="dati">
|
||||||
<i class="fa-solid fa-file-lines me-1"></i> Dati foglio
|
<i class="fa-solid fa-file-lines me-1"></i> Dati foglio
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="ws-tab" data-tab="disegni">
|
${attTabsHtml}
|
||||||
📐 Disegni tecnici <span class="ws-tab-count" id="wsDisegniCount">…</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ws-tab-pane active" data-pane="dati">
|
<div class="ws-tab-pane active" data-pane="dati">
|
||||||
${html}
|
${html}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ws-tab-pane" data-pane="disegni">
|
${attPanesHtml}
|
||||||
<div id="wsDisegniContainer">
|
|
||||||
<div class="text-muted">Caricamento disegni tecnici...</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
$("#worksheetDetailContainer").html(fullHtml);
|
$("#worksheetDetailContainer").html(fullHtml);
|
||||||
loadWorksheetDisegni(ws.idmatrice);
|
loadWorksheetAttachments(ws.idmatrice);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error("Catch loadMatriceWorksheets:", err);
|
console.error("Catch loadMatriceWorksheets:", err);
|
||||||
@@ -495,18 +563,21 @@
|
|||||||
$(".ws-tab-pane").removeClass("active");
|
$(".ws-tab-pane").removeClass("active");
|
||||||
$(`.ws-tab-pane[data-pane="${tab}"]`).addClass("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 (
|
if (
|
||||||
tab === "disegni" &&
|
WS_ATT_KINDS[tab] &&
|
||||||
wsDisegniList.length &&
|
(wsAttLists[tab] || []).length &&
|
||||||
$("#wsDisegnoViewer").is(":empty")
|
$(`#wsViewer_${tab}`).is(":empty")
|
||||||
) {
|
) {
|
||||||
showWorksheetDisegno(0);
|
showWorksheetAttachment(tab, 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on("click", ".ws-disegno-item", function () {
|
$(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 () {
|
$(document).on("click", ".open-worksheet-detail", function () {
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ try {
|
|||||||
description,
|
description,
|
||||||
sort_order,
|
sort_order,
|
||||||
is_disegno,
|
is_disegno,
|
||||||
|
is_strumento,
|
||||||
|
is_ciclo,
|
||||||
created_at,
|
created_at,
|
||||||
updated_at
|
updated_at
|
||||||
FROM matrice_attachments
|
FROM matrice_attachments
|
||||||
@@ -52,6 +54,8 @@ try {
|
|||||||
'description' => $row['description'] ?? '',
|
'description' => $row['description'] ?? '',
|
||||||
'sort_order' => (int)($row['sort_order'] ?? 0),
|
'sort_order' => (int)($row['sort_order'] ?? 0),
|
||||||
'is_disegno' => (int)($row['is_disegno'] ?? 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'])) : '',
|
'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'])) : ''
|
'updated_at' => !empty($row['updated_at']) ? date('d/m/Y H:i', strtotime($row['updated_at'])) : ''
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -27,6 +27,14 @@
|
|||||||
background: #6f42c1;
|
background: #6f42c1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ws-tab[data-tab="strumenti"].active {
|
||||||
|
background: #fd7e14;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ws-tab[data-tab="cicli"].active {
|
||||||
|
background: #0f9d77;
|
||||||
|
}
|
||||||
|
|
||||||
.ws-tab-count {
|
.ws-tab-count {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-width: 24px;
|
min-width: 24px;
|
||||||
@@ -67,6 +75,26 @@
|
|||||||
color: #fff;
|
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 {
|
.ws-disegno-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
+129
-4
@@ -577,6 +577,60 @@ function revisionLabel($rev)
|
|||||||
background: #6f42c1;
|
background: #6f42c1;
|
||||||
color: #fff;
|
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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -1175,9 +1229,11 @@ function revisionLabel($rev)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const list = (data.attachments || []).sort((a, b) =>
|
const flagScore = x =>
|
||||||
(parseInt(b.is_disegno, 10) || 0) - (parseInt(a.is_disegno, 10) || 0)
|
(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");
|
const container = $("#existingAttachmentsList");
|
||||||
container.empty();
|
container.empty();
|
||||||
|
|
||||||
@@ -1196,6 +1252,8 @@ function revisionLabel($rev)
|
|||||||
const createdAt = item.created_at || '';
|
const createdAt = item.created_at || '';
|
||||||
const id = item.id || 0;
|
const id = item.id || 0;
|
||||||
const isDisegno = (parseInt(item.is_disegno, 10) || 0) === 1;
|
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 ?
|
const previewHtml = isImageExt(ext) && filePath ?
|
||||||
`<img src="${escapeHtml(filePath)}" class="attachment-preview-thumb" alt="">` :
|
`<img src="${escapeHtml(filePath)}" class="attachment-preview-thumb" alt="">` :
|
||||||
@@ -1221,7 +1279,7 @@ function revisionLabel($rev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const html = `
|
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 class="d-flex gap-3 align-items-start">
|
||||||
<div>${previewHtml}</div>
|
<div>${previewHtml}</div>
|
||||||
|
|
||||||
@@ -1231,6 +1289,8 @@ function revisionLabel($rev)
|
|||||||
<div class="attachment-meta-title">
|
<div class="attachment-meta-title">
|
||||||
${escapeHtml(fileName)}
|
${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>
|
||||||
<div class="attachment-meta-sub">${badge} ${createdAt ? ' • ' + escapeHtml(createdAt) : ''}</div>
|
<div class="attachment-meta-sub">${badge} ${createdAt ? ' • ' + escapeHtml(createdAt) : ''}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1244,6 +1304,22 @@ function revisionLabel($rev)
|
|||||||
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>
|
<i class="fa-solid fa-compass-drafting"></i>
|
||||||
</button>
|
</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>
|
<button type="button" class="btn btn-sm btn-outline-danger delete-existing-file" data-id="${id}">Elimina</button>
|
||||||
</div>
|
</div>
|
||||||
</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() {
|
$(document).on("click", ".preview-existing-file", function() {
|
||||||
const file = $(this).data("file") || "";
|
const file = $(this).data("file") || "";
|
||||||
const name = $(this).data("name") || "Anteprima file";
|
const name = $(this).data("name") || "Anteprima file";
|
||||||
|
|||||||
@@ -241,7 +241,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?php include('jsinclude.php'); ?>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
|||||||
@@ -245,7 +245,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?php include('jsinclude.php'); ?>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
<!-- jQuery, Bootstrap, DataTables, SweetAlert -->
|
<!-- jQuery, Bootstrap, DataTables, SweetAlert -->
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
<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>
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
|
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
@@ -76,6 +75,68 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
padding: 10px 18px;
|
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>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -298,11 +359,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?php include('jsinclude.php'); ?>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
$('#tabTools').DataTable({
|
$('#tabTools').DataTable({
|
||||||
|
autoWidth: false,
|
||||||
|
initComplete: function() {
|
||||||
|
initColResize();
|
||||||
|
},
|
||||||
order: [
|
order: [
|
||||||
[0, 'asc']
|
[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
|
// ➕ ADD TOOL
|
||||||
$("#addToolForm").on("submit", function(e) {
|
$("#addToolForm").on("submit", function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -13,17 +13,30 @@ function jsonOut($success, $message = '')
|
|||||||
exit;
|
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);
|
$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) {
|
if ($id <= 0) {
|
||||||
jsonOut(false, 'ID allegato non valido');
|
jsonOut(false, 'ID allegato non valido');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isset($campi[$field])) {
|
||||||
|
jsonOut(false, 'Categoria non valida');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
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]);
|
$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) {
|
} catch (Throwable $e) {
|
||||||
jsonOut(false, 'Errore: ' . $e->getMessage());
|
jsonOut(false, 'Errore: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user