Просмотр исходного кода

fix - esportazione excel con #NULL!

ferrari 3 месяцев назад
Родитель
Сommit
d381addb9c

+ 333 - 0
public/assets/js/datatable_export_action.js

@@ -0,0 +1,333 @@
+function colIdxToLetter(n) {
+    let s = "";
+    n = n + 1;
+    while (n > 0) {
+        const m = (n - 1) % 26;
+        s = String.fromCharCode(65 + m) + s;
+        n = Math.floor((n - m) / 26);
+    }
+    return s;
+}
+
+function escapeXmlText(txt) {
+    return String(txt ?? "")
+        .replace(/&/g, "&")
+        .replace(/</g, "&lt;")
+        .replace(/>/g, "&gt;");
+}
+
+function readCellText($cell, sheet, xlsx) {
+    const t = $cell.attr("t");
+    if (t === "inlineStr") {
+        const tNode = $cell.find("is t");
+        return tNode.length ? tNode.text() : "";
+    }
+    if (t === "s") {
+        const v = $cell.find("v").text();
+        const idx = parseInt(v, 10);
+        const sst = xlsx.xl["sharedStrings.xml"];
+        if (!sst) return "";
+        const si = $("sst si", sst).eq(idx);
+        if (!si.length) return "";
+
+        let out = "";
+        si.find("t").each(function () {
+            out += $(this).text();
+        });
+        return out;
+    }
+
+    const vNode = $cell.find("v");
+    return vNode.length ? vNode.text() : "";
+}
+
+function newexportaction(e, dt, button, config, cb) {
+    const self = this;
+    const settings = dt.settings()[0];
+    const isServerSide = settings.oFeatures && settings.oFeatures.bServerSide;
+    const hasAjax = !!settings.ajax;
+
+    const customizeHeaderExcel = function (xlsx) {
+        const sheet = xlsx.xl.worksheets["sheet1.xml"];
+        const styles = xlsx.xl["styles.xml"];
+
+        // --- crea background azzurro ---
+        const fills = $("fills", styles);
+        fills.append(
+            '<fill><patternFill patternType="solid">' +
+                '<fgColor rgb="FFDDEBF7"/><bgColor indexed="64"/>' +
+                "</patternFill></fill>"
+        );
+        const fillId = $("fill", styles).length - 1;
+        fills.attr("count", $("fill", styles).length); // aggiorna count
+
+        // --- crea FONT bold nero ---
+        const fonts = $("fonts", styles);
+        fonts.append(
+            '<font><b/><sz val="11"/><color rgb="FF000000"/><name val="Calibri"/></font>'
+        );
+        const fontId = $("font", styles).length - 1;
+        fonts.attr("count", $("font", styles).length); // aggiorna count
+
+        // --- crea XF senza bordi, bold + fill azzurro ---
+        const cellXfs = $("cellXfs", styles);
+        cellXfs.append(
+            `<xf xfId="0" applyFont="1" applyFill="1" borderId="0" fontId="${fontId}" fillId="${fillId}">
+                    <alignment vertical="center"/>
+                </xf>`
+        );
+        const xfId = $("cellXfs xf", styles).length - 1;
+        cellXfs.attr("count", $("cellXfs xf", styles).length); // aggiorna count
+
+        // --- applica lo stile alla PRIMA riga (header) ---
+        $("row:first c", sheet).attr("s", xfId);
+    };
+
+    const alignLeftCells = function (xlsx, config) {
+        let leftCols = Array.isArray(config.exportLeftCols)
+            ? [...config.exportLeftCols]
+            : [];
+        if (leftCols.length === 0 && dt && dt.columns) {
+            const headerIdxs = [];
+            $(dt.columns().header()).each(function (i, th) {
+                if ($(th).hasClass("export-left")) headerIdxs.push(i);
+            });
+            leftCols = headerIdxs;
+        }
+
+        if (leftCols.length) {
+            const sheet = xlsx.xl.worksheets["sheet1.xml"];
+            const styles = xlsx.xl["styles.xml"];
+
+            const cellXfs = $("cellXfs", styles);
+            cellXfs.append(
+                `<xf xfId="0" applyAlignment="1">
+                        <alignment horizontal="left" vertical="center"/>
+                    </xf>`
+            );
+            const leftXfId = $("cellXfs xf", styles).length - 1;
+            cellXfs.attr("count", $("cellXfs xf", styles).length);
+
+            leftCols.forEach(function (colIdx) {
+                const colLetter = colIdxToLetter(colIdx);
+
+                $('row:not(:first) c[r^="' + colLetter + '"]', sheet).each(
+                    function () {
+                        const cell = $(this);
+                        const sAttr = cell.attr("s");
+                        if (sAttr === undefined) {
+                            cell.attr("s", leftXfId);
+                        } else {
+                            const xfs = $("cellXfs xf", styles);
+                            const baseXf = xfs.eq(parseInt(sAttr, 10)).clone();
+                            if (baseXf.find("alignment").length === 0) {
+                                baseXf.append(
+                                    '<alignment horizontal="left" vertical="center"/>'
+                                );
+                            } else {
+                                baseXf
+                                    .find("alignment")
+                                    .attr("horizontal", "left")
+                                    .attr("vertical", "center");
+                            }
+                            cellXfs.append(baseXf);
+
+                            const newId = $("cellXfs xf", styles).length - 1;
+                            cellXfs.attr(
+                                "count",
+                                $("cellXfs xf", styles).length
+                            );
+                            cell.attr("s", newId);
+                        }
+                    }
+                );
+            });
+        }
+    };
+
+    const forceAllCellsAsText = function (xlsx) {
+        const sheet = xlsx.xl.worksheets["sheet1.xml"];
+        if (!sheet) return;
+
+        $("worksheet sheetData row c", sheet).each(function () {
+            const $cell = $(this);
+            const text = readCellText($cell, sheet, xlsx);
+            // sostituisco contenuto con inline string
+            $cell.attr("t", "inlineStr");
+            $cell.find("v").remove();
+            $cell.find("is").remove();
+            const safe = escapeXmlText(text);
+            $cell.append(`<is><t>${safe}</t></is>`);
+            // NON tocco l’attributo 's' (stile) se già esiste
+        });
+    };
+
+    // --- CLIENT-SIDE ---
+    if (!isServerSide || !hasAjax) {
+        // Esporta tutte le righe lato client
+        const origExportOptions = config.exportOptions
+            ? { ...config.exportOptions }
+            : {};
+        config.exportOptions = config.exportOptions || {};
+        config.exportOptions.modifier = {
+            ...(config.exportOptions.modifier || {}),
+            page: "all",
+        };
+
+        // PDF: tabella full-width
+        // const isPdf = button[0].className.indexOf('buttons-pdf') >= 0;
+        // const origCustomize = config.customize;
+        // if (isPdf) {
+        //     config.customize = function(doc) {
+        //         const table = doc.content[1] && doc.content[1].table ? doc.content[1].table : null;
+        //         if (table && table.body && table.body[0]) {
+        //             table.widths = Array(table.body[0].length).fill('*');
+        //         }
+        //         if (typeof origCustomize === 'function') origCustomize(doc);
+        //     };
+        // }
+
+        const cls = button[0].className;
+
+        if (cls.includes("buttons-copy")) {
+            $.fn.dataTable.ext.buttons.copyHtml5.action.call(
+                self,
+                e,
+                dt,
+                button,
+                config,
+                cb
+            );
+        } else if (cls.includes("buttons-excel")) {
+            const origCustomize = config.customize;
+            config.filename = config.title;
+            config.title = null;
+            config.customize = function (xlsx) {
+                if (typeof origCustomize === "function") origCustomize(xlsx);
+                customizeHeaderExcel(xlsx);
+                alignLeftCells(xlsx, config);
+                forceAllCellsAsText(xlsx);
+            };
+
+            ($.fn.dataTable.ext.buttons.excelHtml5.available(dt, config)
+                ? $.fn.dataTable.ext.buttons.excelHtml5
+                : $.fn.dataTable.ext.buttons.excelFlash
+            ).action.call(self, e, dt, button, config, cb);
+
+            config.customize = origCustomize; // ripristina
+        } else if (cls.includes("buttons-csv")) {
+            ($.fn.dataTable.ext.buttons.csvHtml5.available(dt, config)
+                ? $.fn.dataTable.ext.buttons.csvHtml5
+                : $.fn.dataTable.ext.buttons.csvFlash
+            ).action.call(self, e, dt, button, config, cb);
+        } else if (cls.includes("buttons-pdf")) {
+            ($.fn.dataTable.ext.buttons.pdfHtml5.available(dt, config)
+                ? $.fn.dataTable.ext.buttons.pdfHtml5
+                : $.fn.dataTable.ext.buttons.pdfFlash
+            ).action.call(self, e, dt, button, config, cb);
+        } else if (cls.includes("buttons-print")) {
+            $.fn.dataTable.ext.buttons.print.action.call(
+                self,
+                e,
+                dt,
+                button,
+                config,
+                cb
+            );
+        }
+
+        // Ripristina config
+        config.exportOptions = origExportOptions;
+        // if (isPdf) config.customize = origCustomize;
+
+        if (typeof cb === "function") cb();
+        return;
+    }
+
+    // --- SERVER-SIDE + AJAX: fetch completo poi export ---
+    const info = dt.page.info();
+    const oldStart = info.start;
+    const oldLength = info.length;
+    const targetLength = info.recordsTotal > 0 ? info.recordsTotal : 2147483647;
+
+    dt.one("preXhr", function (e2, s, data) {
+        data.start = 0;
+        data.length = targetLength;
+
+        dt.one("preDraw", function (e3, stg) {
+            const cls = button[0].className;
+
+            if (cls.includes("buttons-copy")) {
+                $.fn.dataTable.ext.buttons.copyHtml5.action.call(
+                    self,
+                    e,
+                    dt,
+                    button,
+                    config,
+                    cb
+                );
+            } else if (cls.includes("buttons-excel")) {
+                const origCustomize = config.customize;
+                config.filename = config.title;
+                config.title = null;
+                config.customize = function (xlsx) {
+                    if (typeof origCustomize === "function")
+                        origCustomize(xlsx);
+                    customizeHeaderExcel(xlsx);
+                    alignLeftCells(xlsx, config);
+                    forceAllCellsAsText(xlsx);
+                };
+
+                ($.fn.dataTable.ext.buttons.excelHtml5.available(dt, config)
+                    ? $.fn.dataTable.ext.buttons.excelHtml5
+                    : $.fn.dataTable.ext.buttons.excelFlash
+                ).action.call(self, e, dt, button, config, cb);
+
+                config.customize = origCustomize;
+            } else if (cls.includes("buttons-csv")) {
+                ($.fn.dataTable.ext.buttons.csvHtml5.available(dt, config)
+                    ? $.fn.dataTable.ext.buttons.csvHtml5
+                    : $.fn.dataTable.ext.buttons.csvFlash
+                ).action.call(self, e, dt, button, config, cb);
+            } else if (cls.includes("buttons-pdf")) {
+                // Full-width PDF
+                // const origCustomize = config.customize;
+                // config.customize = function(doc) {
+                //     const t = doc.content[1] && doc.content[1].table ? doc.content[1].table : null;
+                //     if (t && t.body && t.body[0]) t.widths = Array(t.body[0].length).fill('*');
+                //     if (typeof origCustomize === 'function') origCustomize(doc);
+                // };
+                ($.fn.dataTable.ext.buttons.pdfHtml5.available(dt, config)
+                    ? $.fn.dataTable.ext.buttons.pdfHtml5
+                    : $.fn.dataTable.ext.buttons.pdfFlash
+                ).action.call(self, e, dt, button, config, cb);
+                // config.customize = origCustomize;
+            } else if (cls.includes("buttons-print")) {
+                $.fn.dataTable.ext.buttons.print.action.call(
+                    self,
+                    e,
+                    dt,
+                    button,
+                    config,
+                    cb
+                );
+            }
+
+            dt.one("preXhr", function (e4, s2, data2) {
+                data2.start = oldStart;
+                data2.length = oldLength;
+                stg._iDisplayStart = oldStart;
+            });
+
+            setTimeout(() => {
+                dt.ajax.reload(() => {
+                    if (typeof cb === "function") cb();
+                }, false);
+            }, 0);
+
+            return false;
+        });
+    });
+
+    dt.ajax.reload();
+}

+ 1 - 157
resources/views/layouts/app.blade.php

@@ -463,167 +463,11 @@
   <script src="/assets/js/tablesaw.js"></script>
   <script src="/assets/js/tablesaw-init.js"></script>
   <script src="/assets/js/select2_scroll_fixer.js"></script>
+  <script src="/assets/js/datatable_export_action.js"></script>
 
 
     @livewireScripts
 
-    <script>
-    function newexportaction(e, dt, button, config, cb) {
-        const self = this;
-        const settings = dt.settings()[0];
-        const isServerSide = settings.oFeatures && settings.oFeatures.bServerSide;
-        const hasAjax = !!settings.ajax;
-
-        const customizeExcel = function (xlsx) {
-            const sheet  = xlsx.xl.worksheets['sheet1.xml'];
-            const styles = xlsx.xl['styles.xml'];
-
-            // --- crea background azzurro ---
-            const fills = $('fills', styles);
-            fills.append(
-                '<fill><patternFill patternType="solid">' +
-                    '<fgColor rgb="FFDDEBF7"/><bgColor indexed="64"/>' +
-                '</patternFill></fill>'
-            );
-            const fillId = $('fill', styles).length - 1;
-            fills.attr('count', $('fill', styles).length); // aggiorna count
-
-            // --- crea FONT bold nero ---
-            const fonts = $('fonts', styles);
-            fonts.append('<font><b/><sz val="11"/><color rgb="FF000000"/><name val="Calibri"/></font>');
-            const fontId = $('font', styles).length - 1;
-            fonts.attr('count', $('font', styles).length); // aggiorna count
-
-            // --- crea XF senza bordi, bold + fill azzurro ---
-            const cellXfs = $('cellXfs', styles);
-            cellXfs.append(
-                `<xf xfId="0" applyFont="1" applyFill="1" borderId="0" fontId="${fontId}" fillId="${fillId}">
-                    <alignment vertical="center"/>
-                </xf>`
-            );
-            const xfId = $('cellXfs xf', styles).length - 1;
-            cellXfs.attr('count', $('cellXfs xf', styles).length); // aggiorna count
-
-            // --- applica lo stile alla PRIMA riga (header) ---
-            $('row:first c', sheet).attr('s', xfId);
-        };
-
-
-        // --- CLIENT-SIDE ---
-        if (!isServerSide || !hasAjax) {
-            // Esporta tutte le righe lato client
-            const origExportOptions = config.exportOptions ? { ...config.exportOptions } : {};
-            config.exportOptions = config.exportOptions || {};
-            config.exportOptions.modifier = { ...(config.exportOptions.modifier || {}), page: "all" };
-
-            // PDF: tabella full-width
-            // const isPdf = button[0].className.indexOf('buttons-pdf') >= 0;
-            // const origCustomize = config.customize;
-            // if (isPdf) {
-            //     config.customize = function(doc) {
-            //         const table = doc.content[1] && doc.content[1].table ? doc.content[1].table : null;
-            //         if (table && table.body && table.body[0]) {
-            //             table.widths = Array(table.body[0].length).fill('*');
-            //         }
-            //         if (typeof origCustomize === 'function') origCustomize(doc);
-            //     };
-            // }
-
-            const cls = button[0].className;
-
-            if (cls.includes("buttons-copy")) {
-                $.fn.dataTable.ext.buttons.copyHtml5.action.call(self, e, dt, button, config, cb);
-            } else if (cls.includes("buttons-excel")) {
-                const origCustomize = config.customize;
-                config.filename = config.title;
-                config.title = null;
-                config.customize = function (xlsx) {
-                    if (typeof origCustomize === "function") origCustomize(xlsx);
-                    customizeExcel(xlsx);
-                };
-
-                ($.fn.dataTable.ext.buttons.excelHtml5.available(dt, config) ? $.fn.dataTable.ext.buttons.excelHtml5 : $.fn.dataTable.ext.buttons.excelFlash).action.call(self, e, dt, button, config, cb);
-
-                config.customize = origCustomize; // ripristina
-            } else if (cls.includes("buttons-csv")) {
-                ($.fn.dataTable.ext.buttons.csvHtml5.available(dt, config) ? $.fn.dataTable.ext.buttons.csvHtml5 : $.fn.dataTable.ext.buttons.csvFlash).action.call(self, e, dt, button, config, cb);
-            } else if (cls.includes("buttons-pdf")) {
-                ($.fn.dataTable.ext.buttons.pdfHtml5.available(dt, config) ? $.fn.dataTable.ext.buttons.pdfHtml5 : $.fn.dataTable.ext.buttons.pdfFlash).action.call(self, e, dt, button, config, cb);
-            } else if (cls.includes("buttons-print")) {
-                $.fn.dataTable.ext.buttons.print.action.call(self, e, dt, button, config, cb);
-            }
-
-            // Ripristina config
-            config.exportOptions = origExportOptions;
-            // if (isPdf) config.customize = origCustomize;
-
-            if (typeof cb === "function") cb();
-            return;
-        }
-
-        // --- SERVER-SIDE + AJAX: fetch completo poi export ---
-        const info = dt.page.info();
-        const oldStart = info.start;
-        const oldLength = info.length;
-        const targetLength = info.recordsTotal > 0 ? info.recordsTotal : 2147483647;
-
-        dt.one("preXhr", function (e2, s, data) {
-            data.start = 0;
-            data.length = targetLength;
-
-            dt.one("preDraw", function (e3, stg) {
-                const cls = button[0].className;
-
-                if (cls.includes("buttons-copy")) {
-                    $.fn.dataTable.ext.buttons.copyHtml5.action.call(self, e, dt, button, config, cb);
-                } else if (cls.includes("buttons-excel")) {
-                    const origCustomize = config.customize;
-                    config.filename = config.title;
-                    config.title = null;
-                    config.customize = function (xlsx) {
-                        if (typeof origCustomize === "function") origCustomize(xlsx);
-                        customizeExcel(xlsx);
-                    };
-
-                    ($.fn.dataTable.ext.buttons.excelHtml5.available(dt, config) ? $.fn.dataTable.ext.buttons.excelHtml5 : $.fn.dataTable.ext.buttons.excelFlash).action.call(self, e, dt, button, config, cb);
-
-                    config.customize = origCustomize;
-                } else if (cls.includes("buttons-csv")) {
-                    ($.fn.dataTable.ext.buttons.csvHtml5.available(dt, config) ? $.fn.dataTable.ext.buttons.csvHtml5 : $.fn.dataTable.ext.buttons.csvFlash).action.call(self, e, dt, button, config, cb);
-                } else if (cls.includes("buttons-pdf")) {
-                    // Full-width PDF
-                    // const origCustomize = config.customize;
-                    // config.customize = function(doc) {
-                    //     const t = doc.content[1] && doc.content[1].table ? doc.content[1].table : null;
-                    //     if (t && t.body && t.body[0]) t.widths = Array(t.body[0].length).fill('*');
-                    //     if (typeof origCustomize === 'function') origCustomize(doc);
-                    // };
-                    ($.fn.dataTable.ext.buttons.pdfHtml5.available(dt, config) ? $.fn.dataTable.ext.buttons.pdfHtml5 : $.fn.dataTable.ext.buttons.pdfFlash).action.call(self, e, dt, button, config, cb);
-                    // config.customize = origCustomize;
-                } else if (cls.includes("buttons-print")) {
-                    $.fn.dataTable.ext.buttons.print.action.call(self, e, dt, button, config, cb);
-                }
-
-                dt.one("preXhr", function (e4, s2, data2) {
-                    data2.start = oldStart;
-                    data2.length = oldLength;
-                    stg._iDisplayStart = oldStart;
-                });
-
-                setTimeout(() => {
-                    dt.ajax.reload(() => {
-                        if (typeof cb === "function") cb();
-                    }, false);
-                }, 0);
-
-                return false;
-            });
-        });
-
-        dt.ajax.reload();
-    }
-    </script>
-
     @stack('scripts')
 
     <script>

+ 2 - 1
resources/views/livewire/records_out.blade.php

@@ -1893,7 +1893,8 @@
                                         title: date_export + 'Uscite',
                                         exportOptions: {
                                             columns: ":not(':last')"
-                                        }
+                                        },
+                                        exportLeftCols: [0]
                                     },
                                     {
                                         extend: 'pdfHtml5',