Luckysheet + Exceljs:H5实现Excel在线编辑、导入、导出及上传服务器的示例代码(完整版demo)

news2024/11/24 20:59:51

 

创建xeditor.html 

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>Hello World!</title>
    <!-- <link rel='stylesheet' href='./luckysheet/plugins/css/pluginsCss.css' />
    <link rel='stylesheet' href='./luckysheet/plugins/plugins.css' />
    <link rel='stylesheet' href='./luckysheet/css/luckysheet.css' />
    <link rel='stylesheet' href='./luckysheet/assets/iconfont/iconfont.css' />
    <script src="./luckysheet/plugins/js/plugin.js"></script>
    <script src="./luckysheet/luckysheet.umd.js"></script> -->

    <!-- 引入luckysheet,用于渲染表格 -->
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/css/pluginsCss.css' />
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/plugins.css' />
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/css/luckysheet.css' />
    <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/assets/iconfont/iconfont.css' />
    <script src="https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/js/plugin.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/luckysheet.umd.js"></script>

    <!-- 引入exceljs、FileSaver,用于luckysheet表格转xlsx文件 -->
    <script src="https://cdn.bootcdn.net/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/exceljs/4.3.0/exceljs.js"></script>
    <script>
        $(function () {
            //Configuration item
            var options = {
                container: 'luckysheet', //luckysheet is the container id
                showinfobar: false,
                title: '在线表格', // 设定表格名称
                lang: 'zh' // 设定表格语言
            }
            luckysheet.create(options)
        });
    </script>
</head>

<body>
    <div id="lucky-mask-demo"
        style="position: absolute;z-index: 1000000;left: 0px;top: 0px;bottom: 0px;right: 0px; background: rgba(255, 255, 255, 0.8); text-align: center;font-size: 40px;align-items:center;justify-content: center;display: none;">
        download...</div>
    <p style="text-align:center;"> <input style="font-size:16px;" type="file" id="Luckyexcel-demo-file"
            name="Luckyexcel-demo-file" change="demoHandler" /> 或加载远程 xlsx 文件:
        <select style="height: 27px;top: -2px;position: relative;" id="Luckyexcel-select-demo">
            <option value="">选择网络文件</option>
            <option value="https://minio.cnbabylon.com/public/luckysheet/money-manager-2.xlsx">Money Manager.xlsx</option>
            <option value="https://minio.cnbabylon.com/public/luckysheet/Activity%20costs%20tracker.xlsx">Activity costs tracker.xlsx</option>
            <option value="https://minio.cnbabylon.com/public/luckysheet/House%20cleaning%20checklist.xlsx">House cleaning checklist.xlsx</option>
            <option value="https://minio.cnbabylon.com/public/luckysheet/Student%20assignment%20planner.xlsx">Student assignment planner.xlsx</option>
            <option value="https://minio.cnbabylon.com/public/luckysheet/Credit%20card%20tracker.xlsx">Credit card tracker.xlsx</option>
            <option value="https://minio.cnbabylon.com/public/luckysheet/Blue%20timesheet.xlsx">Blue timesheet.xlsx</option>
            <option value="https://minio.cnbabylon.com/public/luckysheet/Student%20calendar%20%28Mon%29.xlsx">Student calendar (Mon).xlsx</option>
            <option value="https://minio.cnbabylon.com/public/luckysheet/Blue%20mileage%20and%20expense%20report.xlsx">Blue mileage and expense report.xlsx</option>
        </select>
        <a href="javascript:void(0)" id="Luckyexcel-downlod-file">下载 xlsx 文件</a>
        <a href="javascript:void(0)" id="Luckyexcel-upload-file">上传到服务器</a>
    </p>
    <div id="luckysheet"
        style="margin:0px;padding:0px;position:absolute;width:100%;left: 0px;top: 50px;bottom: 0px;outline: none;">
    </div>
    <!-- <script src="luckyexcel.umd.js"></script> -->
    <script src="https://cdn.jsdelivr.net/npm/luckyexcel/dist/luckyexcel.umd.js"></script>

    <!-- <script type="module">
            import l from './luckyexcel.js';
            console.info('=====',l)
            // window.onload = () => {
            //     let upload = document.getElementById("file");
            //     upload.addEventListener("change", function(evt){
            //         var files = evt.target.files;   
            //         importFile(files[0]);
            //     });
            // }
        </script> -->
    <script>
        let fullName=''; // 正在编辑的Excel文件名,包含后缀名
        function demoHandler() {
            let upload = document.getElementById("Luckyexcel-demo-file");
            let selectADemo = document.getElementById("Luckyexcel-select-demo");
            let downlodDemo = document.getElementById("Luckyexcel-downlod-file");
            let uploadDemo = document.getElementById("Luckyexcel-upload-file");
            let mask = document.getElementById("lucky-mask-demo");
            if (upload) {

                window.onload = () => {

                    upload.addEventListener("change", function (evt) {
                        var files = evt.target.files;
                        if (files == null || files.length == 0) {
                            alert("No files wait for import");
                            return;
                        }

                        let name = files[0].name;
                        let suffixArr = name.split("."), suffix = suffixArr[suffixArr.length - 1];
                        if (suffix != "xlsx") {
                            alert("Currently only supports the import of xlsx files");
                            return;
                        }
                        fullName=name;
                        LuckyExcel.transformExcelToLucky(files[0], function (exportJson, luckysheetfile) {

                            if (exportJson.sheets == null || exportJson.sheets.length == 0) {
                                alert("Failed to read the content of the excel file, currently does not support xls files!");
                                return;
                            }
                            window.luckysheet.destroy();

                            window.luckysheet.create({
                                container: 'luckysheet', //luckysheet is the container id
                                showinfobar: false,
                                data: exportJson.sheets,
                                title: '在线表格',
                                userInfo: exportJson.info.name.creator,
                                lang: 'zh'
                            });
                        });
                    });

                    selectADemo.addEventListener("change", function (evt) {
                        var obj = selectADemo;
                        var index = obj.selectedIndex;
                        var value = obj.options[index].value;
                        var name = obj.options[index].innerHTML;
                        if (value == "") {
                            return;
                        }
                        fullName=name;
                        mask.style.display = "flex";
                        LuckyExcel.transformExcelToLuckyByUrl(value, name, function (exportJson, luckysheetfile) {

                            if (exportJson.sheets == null || exportJson.sheets.length == 0) {
                                alert("Failed to read the content of the excel file, currently does not support xls files!");
                                return;
                            }
                            console.log(exportJson, luckysheetfile);
                            mask.style.display = "none";
                            window.luckysheet.destroy();

                            window.luckysheet.create({
                                container: 'luckysheet', //luckysheet is the container id
                                showinfobar: false,
                                data: exportJson.sheets,
                                title: '在线表格',
                                userInfo: exportJson.info.name.creator,
                                lang: 'zh'
                            });
                        });
                    });
                    
                    uploadDemo.addEventListener("click", function (evt) {
                        uploadExcel(window.luckysheet.getAllSheets(), fullName)  // 上传到服务器
                    });

                    downlodDemo.addEventListener("click", function (evt) {
                        exportExcelFront(window.luckysheet.getAllSheets(), fullName) // 下载Excel

                        // var obj = selectADemo;
                        // var index = obj.selectedIndex;
                        // var value = obj.options[index].value;
                        // if (value.length == 0) {
                        //     alert("Please select a demo file");
                        //     return;
                        // }
                        // var elemIF = document.getElementById("Lucky-download-frame");
                        // if (elemIF == null) {
                        //     elemIF = document.createElement("iframe");
                        //     elemIF.style.display = "none";
                        //     elemIF.id = "Lucky-download-frame";
                        //     document.body.appendChild(elemIF);
                        // }
                        // elemIF.src = value;

                    });
                }
            }
        }
        demoHandler();

        /**
         * 上传到服务器
         * @param luckysheet    -> luckysheet的所有sheet
         * @param name          -> 保存文件名(如:a.xlsx)
         * @param excelType     -> office/wps
         */
        var uploadExcel = function(luckysheet, name, excelType) {
            // 1.创建工作簿,可以为工作簿添加属性
            const workbook = new ExcelJS.Workbook()
            // 2.创建表格,第二个参数可以配置创建什么样的工作表
            luckysheet.forEach(function (table) {
                // debugger
                if (table.data.length === 0) return true
                const worksheet = workbook.addWorksheet(table.name)
                const merge = (table.config && table.config.merge) || {}        //合并单元格
                const borderInfo = (table.config && table.config.borderInfo) || {}      //边框
                const columnWidth = (table.config && table.config.columnlen) || {}    //列宽
                const rowHeight = (table.config && table.config.rowlen) || {}      //行高
                const frozen = table.frozen || {}       //冻结
                const rowhidden = (table.config && table.config.rowhidden) || {}    //行隐藏
                const colhidden = (table.config && table.config.colhidden) || {}    //列隐藏
                const filterSelect = table.filter_select || {}    //筛选
                const images = table.images || {}   //图片
                // console.log(table)
                const hide = table.hide;    //工作表 sheet 1隐藏
                if (hide === 1) {
                    // 隐藏工作表
                    worksheet.state = 'hidden';
                }
                setStyleAndValue(table.data, worksheet)
                setMerge(merge, worksheet)
                setBorder(borderInfo, worksheet)
                setImages(images, worksheet, workbook)
                setColumnWidth(columnWidth, worksheet)
                //行高设置50导出后在ms-excel中打开显示25,在wps-excel中打开显示50这个bug不会修复
                setRowHeight(rowHeight, worksheet, excelType)
                setFrozen(frozen, worksheet)
                setRowHidden(rowhidden, worksheet)
                setColHidden(colhidden, worksheet)
                setFilter(filterSelect, worksheet)
                return true
            })

            // 4.写入 buffer
            const buffer = workbook.xlsx.writeBuffer().then(data => {
                const blob = new Blob([data], {
                    type: 'application/vnd.ms-excel;charset=utf-8'
                })

                // 创建FormData对象
                const formData = new FormData();
                formData.append('file', blob, `${name}`);
                // 创建XMLHttpRequest对象
                const xhr = new XMLHttpRequest();
                // 配置请求
                xhr.open('POST', 'http://127.0.0.1:3000/upload', true);
                // 设置请求完成的回调函数
                xhr.onload = function () {
                    if (xhr.status === 200) {
                        alert('已上传成功!')
                        console.log('Success:', xhr.responseText);
                    } else {
                        alert('上传失败!'+xhr.statusText)
                        console.error('Error:', xhr.statusText);
                    }
                };
                // 设置请求失败的回调函数
                xhr.onerror = function () {
                    console.error('Network error occurred');
                };
                // 设置请求超时的回调函数(可选)
                xhr.ontimeout = function (e) {
                    console.error('Request timed out');
                };
                // 设置请求超时时间(可选)
                xhr.timeout = 5000; // 5秒
                // 发送FormData对象
                xhr.send(formData);
                // 设置请求头(可选,某些浏览器可能不需要)
                xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
            })

            return buffer
        }

        /**
         * 下载Excel
         * @param luckysheet    -> luckysheet的所有sheet
         * @param name          -> 保存文件名(如:a.xlsx)
         * @param excelType     -> office/wps
         */
        var exportExcelFront = function(luckysheet, name, excelType) {
            // 1.创建工作簿,可以为工作簿添加属性
            const workbook = new ExcelJS.Workbook()
            // 2.创建表格,第二个参数可以配置创建什么样的工作表
            luckysheet.forEach(function (table) {
                // debugger
                if (table.data.length === 0) return true
                const worksheet = workbook.addWorksheet(table.name)
                const merge = (table.config && table.config.merge) || {}        //合并单元格
                const borderInfo = (table.config && table.config.borderInfo) || {}      //边框
                const columnWidth = (table.config && table.config.columnlen) || {}    //列宽
                const rowHeight = (table.config && table.config.rowlen) || {}      //行高
                const frozen = table.frozen || {}       //冻结
                const rowhidden = (table.config && table.config.rowhidden) || {}    //行隐藏
                const colhidden = (table.config && table.config.colhidden) || {}    //列隐藏
                const filterSelect = table.filter_select || {}    //筛选
                const images = table.images || {}   //图片
                // console.log(table)
                const hide = table.hide;    //工作表 sheet 1隐藏
                if (hide === 1) {
                    // 隐藏工作表
                    worksheet.state = 'hidden';
                }
                setStyleAndValue(table.data, worksheet)
                setMerge(merge, worksheet)
                setBorder(borderInfo, worksheet)
                setImages(images, worksheet, workbook)
                setColumnWidth(columnWidth, worksheet)
                //行高设置50导出后在ms-excel中打开显示25,在wps-excel中打开显示50这个bug不会修复
                setRowHeight(rowHeight, worksheet, excelType)
                setFrozen(frozen, worksheet)
                setRowHidden(rowhidden, worksheet)
                setColHidden(colhidden, worksheet)
                setFilter(filterSelect, worksheet)
                return true
            })

            // 4.写入 buffer
            const buffer = workbook.xlsx.writeBuffer().then(data => {
                const blob = new Blob([data], {
                    type: 'application/vnd.ms-excel;charset=utf-8'
                })

                // 浏览器下载文件的示例代码
                console.log("导出成功!")
                saveAs(blob, `${name}`)
            })

            return buffer
        }


        /**
         * 列宽
         * @param columnWidth
         * @param worksheet
         */
        var setColumnWidth = function (columnWidth, worksheet) {
            for (let key in columnWidth) {
                worksheet.getColumn(parseInt(key) + 1).width = columnWidth[key] / 7.5
            }
        }

        /**
         * 行高
         * @param rowHeight
         * @param worksheet
         * @param excelType
         */
        var setRowHeight = function (rowHeight, worksheet, excelType) {
            //导出的文件用wps打开和用excel打开显示的行高大一倍
            if (excelType == "wps") {
                for (let key in rowHeight) {
                    worksheet.getRow(parseInt(key) + 1).height = rowHeight[key] * 0.75
                }
            }
            if (excelType == "office" || excelType == undefined) {
                for (let key in rowHeight) {
                    worksheet.getRow(parseInt(key) + 1).height = rowHeight[key] * 1.5
                }
            }
        }

        /**
         * 合并单元格
         * @param luckyMerge
         * @param worksheet
         */
        var setMerge = function (luckyMerge = {}, worksheet) {
            const mergearr = Object.values(luckyMerge)
            mergearr.forEach(function (elem) {
                // elem格式:{r: 0, c: 0, rs: 1, cs: 2}
                // 按开始行,开始列,结束行,结束列合并(相当于 K10:M12)
                worksheet.mergeCells(
                    elem.r + 1,
                    elem.c + 1,
                    elem.r + elem.rs,
                    elem.c + elem.cs
                )
            })
        }

        /**
         * 设置边框
         * @param luckyBorderInfo
         * @param worksheet
         */
        var setBorder = function (luckyBorderInfo, worksheet) {
            if (!Array.isArray(luckyBorderInfo)) return

            //合并边框信息
            var mergeCellBorder = function (border1, border2) {
                if (undefined === border1 || Object.keys(border1).length === 0) return border2;
                return Object.assign({}, border1, border2)
            }

            // console.log('luckyBorderInfo', luckyBorderInfo)
            luckyBorderInfo.forEach(function (elem) {
                // 现在只兼容到borderType 为range的情况
                // console.log('ele', elem)
                if (elem.rangeType === 'range') {
                    let border = borderConvert(elem.borderType, elem.style, elem.color)
                    let rang = elem.range[0]
                    let row = rang.row
                    let column = rang.column

                    let rowBegin = row[0]
                    let rowEnd = row[1]
                    let colBegin = column[0]
                    let colEnd = column[1]
                    //处理外边框的情况 没有直接对应的外边框 需要转换成上下左右
                    if (border.all) {//全部边框
                        let b = border.all
                        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
                            for (let y = column[0] + 1; y <= column[1] + 1; y++) {
                                let border = {}
                                border['top'] = b;
                                border['bottom'] = b;
                                border['left'] = b;
                                border['right'] = b;
                                worksheet.getCell(i, y).border = border
                                // console.log(i, y, worksheet.getCell(i, y).border)
                            }
                        }
                    } else if (border.top) {//上边框
                        let b = border.top
                        let i = row[0] + 1;
                        for (let y = column[0] + 1; y <= column[1] + 1; y++) {
                            let border = {}
                            border['top'] = b;
                            worksheet.getCell(i, y).border = border
                            // console.log(i, y, worksheet.getCell(i, y).border)
                        }
                    } else if (border.right) {//右边框
                        let b = border.right
                        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
                            let y = column[1] + 1;
                            let border = {}
                            border['right'] = b;
                            worksheet.getCell(i, y).border = border
                            // console.log(i, y, worksheet.getCell(i, y).border)
                        }
                    } else if (border.bottom) {//下边框
                        let b = border.bottom
                        let i = row[1] + 1;
                        for (let y = column[0] + 1; y <= column[1] + 1; y++) {
                            let border = {}

                            border['bottom'] = b;
                            worksheet.getCell(i, y).border = border
                            // console.log(i, y, worksheet.getCell(i, y).border)
                        }
                    } else if (border.left) {//左边框
                        let b = border.left
                        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
                            let y = column[0] + 1;
                            let border = {}
                            border['left'] = b;
                            worksheet.getCell(i, y).border = border
                            // console.log(i, y, worksheet.getCell(i, y).border)
                        }
                    } else if (border.outside) {//外边框
                        let b = border.outside
                        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
                            for (let y = column[0] + 1; y <= column[1] + 1; y++) {
                                let border = {}
                                if (i === rowBegin + 1) {
                                    border['top'] = b
                                }
                                if (i === rowEnd + 1) {
                                    border['bottom'] = b
                                }
                                if (y === colBegin + 1) {
                                    border['left'] = b
                                }
                                if (y === colEnd + 1) {
                                    border['right'] = b
                                }
                                let border1 = worksheet.getCell(i, y).border
                                worksheet.getCell(i, y).border = mergeCellBorder(border1, border)
                                // console.log(i, y, worksheet.getCell(i, y).border)
                            }
                        }
                    } else if (border.inside) {//内边框
                        let b = border.inside
                        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
                            for (let y = column[0] + 1; y <= column[1] + 1; y++) {
                                let border = {}
                                if (i !== rowBegin + 1) {
                                    border['top'] = b
                                }
                                if (i !== rowEnd + 1) {
                                    border['bottom'] = b
                                }
                                if (y !== colBegin + 1) {
                                    border['left'] = b
                                }
                                if (y !== colEnd + 1) {
                                    border['right'] = b
                                }
                                let border1 = worksheet.getCell(i, y).border
                                worksheet.getCell(i, y).border = mergeCellBorder(border1, border)
                                // console.log(i, y, worksheet.getCell(i, y).border)
                            }
                        }
                    } else if (border.horizontal) {//内侧水平边框
                        let b = border.horizontal
                        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
                            for (let y = column[0] + 1; y <= column[1] + 1; y++) {
                                let border = {}
                                if (i === rowBegin + 1) {
                                    border['bottom'] = b
                                } else if (i === rowEnd + 1) {
                                    border['top'] = b
                                } else {
                                    border['top'] = b
                                    border['bottom'] = b
                                }
                                let border1 = worksheet.getCell(i, y).border
                                worksheet.getCell(i, y).border = mergeCellBorder(border1, border)
                                // console.log(i, y, worksheet.getCell(i, y).border)
                            }
                        }
                    } else if (border.vertical) {//内侧垂直边框
                        let b = border.vertical
                        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
                            for (let y = column[0] + 1; y <= column[1] + 1; y++) {
                                let border = {}
                                if (y === colBegin + 1) {
                                    border['right'] = b
                                } else if (y === colEnd + 1) {
                                    border['left'] = b
                                } else {
                                    border['left'] = b
                                    border['right'] = b
                                }
                                let border1 = worksheet.getCell(i, y).border
                                worksheet.getCell(i, y).border = mergeCellBorder(border1, border)
                                // console.log(i, y, worksheet.getCell(i, y).border)
                            }
                        }
                    } else if (border.none) {//当luckysheet边框为border-none的时候表示没有边框 则将对应的单元格border清空
                        for (let i = row[0] + 1; i <= row[1] + 1; i++) {
                            for (let y = column[0] + 1; y <= column[1] + 1; y++) {
                                worksheet.getCell(i, y).border = {}
                                // console.log(i, y, worksheet.getCell(i, y).border)
                            }
                        }
                    }
                }
                if (elem.rangeType === 'cell') {
                    // col_index: 2
                    // row_index: 1
                    // b: {
                    //   color: '#d0d4e3'
                    //   style: 1
                    // }
                    const { col_index, row_index } = elem.value
                    const borderData = Object.assign({}, elem.value)
                    delete borderData.col_index
                    delete borderData.row_index
                    let border = addborderToCell(borderData, row_index, col_index)
                    let border1 = worksheet.getCell(row_index + 1, col_index + 1).border;
                    worksheet.getCell(row_index + 1, col_index + 1).border = mergeCellBorder(border1, border)
                    // console.log(row_index + 1, col_index + 1, worksheet.getCell(row_index + 1, col_index + 1).border)
                }
            })
        }


        /**
         * 设置带样式的值
         * @param cellArr
         * @param worksheet
         */
        var setStyleAndValue = function (cellArr, worksheet) {
            if (!Array.isArray(cellArr)) return
            cellArr.forEach(function (row, rowid) {
                row.every(function (cell, columnid) {
                    if (!cell) return true
                    let fill = fillConvert(cell.bg)

                    let font = fontConvert(
                        cell.ff,
                        cell.fc,
                        cell.bl,
                        cell.it,
                        cell.fs,
                        cell.cl,
                        cell.un
                    )
                    let alignment = alignmentConvert(cell.vt, cell.ht, cell.tb, cell.tr)
                    let value = ''

                    if (cell.f) {
                        value = { formula: cell.f, result: cell.v }
                    } else if (!cell.v && cell.ct && cell.ct.s) {
                        // xls转为xlsx之后,内部存在不同的格式,都会进到富文本里,即值不存在与cell.v,而是存在于cell.ct.s之后
                        let richText = [];
                        let cts = cell.ct.s
                        for (let i = 0; i < cts.length; i++) {
                            let rt = {
                                text: cts[i].v,
                                font: fontConvert(cts[i].ff, cts[i].fc, cts[i].bl, cts[i].it, cts[i].fs, cts[i].cl, cts[i].un)
                            }
                            richText.push(rt)
                        }
                        value = {
                            richText: richText
                        };

                    } else {
                        //设置值为数字格式
                        if (cell.v !== undefined && cell.v !== '') {
                            var v = +cell.v;
                            if (isNaN(v)) v = cell.v
                            value = v
                        }
                    }
                    //  style 填入到_value中可以实现填充色
                    let letter = createCellPos(columnid)
                    let target = worksheet.getCell(letter + (rowid + 1))
                    // console.log('1233', letter + (rowid + 1))
                    for (const key in fill) {
                        target.fill = fill
                        break
                    }
                    target.font = font
                    target.alignment = alignment
                    target.value = value

                    try {
                        //设置单元格格式
                        target.numFmt = cell.ct.fa;
                    } catch (e) {
                        console.warn(e)
                    }

                    return true
                })
            })
        }

        /**
         * 设置图片
         * @param images
         * @param worksheet
         * @param workbook
         */
        var setImages = function (images, worksheet, workbook) {
            if (typeof images != "object") return;
            for (let key in images) {
                // console.log(images[key]);
                // "data:image/png;base64,iVBORw0KG..."
                // 通过 base64  将图像添加到工作簿
                const myBase64Image = images[key].src;
                //位置
                const tl = { col: images[key].default.left / 72, row: images[key].default.top / 19 }
                // 大小
                const ext = { width: images[key].default.width, height: images[key].default.height }
                const imageId = workbook.addImage({
                    base64: myBase64Image,
                    //extension: 'png',
                });
                worksheet.addImage(imageId, {
                    tl: tl,
                    ext: ext
                });
            }
        }

        /**
         * 冻结行列
         * @param frozen
         * @param worksheet
         */
        var setFrozen = function (frozen = {}, worksheet) {
            switch (frozen.type) {
                // 冻结首行
                case 'row': {
                    worksheet.views = [
                        { state: 'frozen', xSplit: 0, ySplit: 1 }
                    ];
                    break
                }
                // 冻结首列
                case 'column': {
                    worksheet.views = [
                        { state: 'frozen', xSplit: 1, ySplit: 0 }
                    ];
                    break
                }
                // 冻结行列
                case 'both': {
                    worksheet.views = [
                        { state: 'frozen', xSplit: 1, ySplit: 1 }
                    ];
                    break
                }
                // 冻结行到选区
                case 'rangeRow': {
                    let row = frozen.range.row_focus + 1
                    worksheet.views = [
                        { state: 'frozen', xSplit: 0, ySplit: row }
                    ];
                    break
                }
                // 冻结列到选区
                case 'rangeColumn': {
                    let column = frozen.range.column_focus + 1
                    worksheet.views = [
                        { state: 'frozen', xSplit: column, ySplit: 0 }
                    ];
                    break
                }
                // 冻结行列到选区
                case 'rangeBoth': {
                    let row = frozen.range.row_focus + 1
                    let column = frozen.range.column_focus + 1
                    worksheet.views = [
                        { state: 'frozen', xSplit: column, ySplit: row }
                    ];
                }

            }

        }

        /**
         * 行隐藏
         * @param rowhidden
         * @param worksheet
         */
        var setRowHidden = function (rowhidden = {}, worksheet) {
            for (const key in rowhidden) {
                //如果当前行没有内容则隐藏不生效
                const row = worksheet.getRow(parseInt(key) + 1)
                row.hidden = true;
            }
        }

        /**
         * 列隐藏
         * @param colhidden
         * @param worksheet
         */
        var setColHidden = function (colhidden = {}, worksheet) {
            for (const key in colhidden) {
                const column = worksheet.getColumn(parseInt(key) + 1)
                column.hidden = true;
            }
        }

        /**
         * 自动筛选器
         * @param filter
         * @param worksheet
         */
        var setFilter = function (filter = {}, worksheet) {
            if (Object.keys(filter).length === 0) return
            const from = {
                row: filter.row[0] + 1,
                column: filter.column[0] + 1
            }

            const to = {
                row: filter.row[1] + 1,
                column: filter.column[1] + 1
            }

            worksheet.autoFilter = {
                from: from,
                to: to
            }

        }

        var fillConvert = function (bg) {
            if (!bg) {
                return {}
            }
            // const bgc = bg.replace('#', '')
            let fill = {
                type: 'pattern',
                pattern: 'solid',
                fgColor: { argb: bg.startsWith("#") ? bg.replace('#', '') : colorRGBtoHex(bg).replace("#", "") },
            }
            return fill;
        }

        var fontConvert = function (
            ff = 0,
            fc = '#000000',
            bl = 0,
            it = 0,
            fs = 10,
            cl = 0,
            ul = 0
        ) {
            // luckysheet:ff(样式), fc(颜色), bl(粗体), it(斜体), fs(大小), cl(删除线), ul(下划线)
            const luckyToExcel = {
                0: '微软雅黑',
                1: '宋体(Song)',
                2: '黑体(ST Heiti)',
                3: '楷体(ST Kaiti)',
                4: '仿宋(ST FangSong)',
                5: '新宋体(ST Song)',
                6: '华文新魏',
                7: '华文行楷',
                8: '华文隶书',
                9: 'Arial',
                10: 'Times New Roman ',
                11: 'Tahoma ',
                12: 'Verdana',
                num2bl: function (num) {
                    return num !== 0
                }
            }
            // 出现Bug,导入的时候ff为luckyToExcel的val

            let font = {
                name: typeof ff === 'number' ? luckyToExcel[ff] : ff,
                family: 1,
                size: fs,
                color: { argb: fc.startsWith("#") ? fc.replace('#', '') : colorRGBtoHex(fc).replace("#", "") },
                bold: luckyToExcel.num2bl(bl),
                italic: luckyToExcel.num2bl(it),
                underline: luckyToExcel.num2bl(ul),
                strike: luckyToExcel.num2bl(cl)
            }

            return font
        }

        var alignmentConvert = function (
            vt = 'default',
            ht = 'default',
            tb = 'default',
            tr = 'default'
        ) {
            // luckysheet:vt(垂直), ht(水平), tb(换行), tr(旋转)
            const luckyToExcel = {
                vertical: {
                    0: 'middle',
                    1: 'top',
                    2: 'bottom',
                    default: 'middle'
                },
                horizontal: {
                    0: 'center',
                    1: 'left',
                    2: 'right',
                    default: 'center'
                },
                wrapText: {
                    0: false,
                    1: false,
                    2: true,
                    default: false
                },
                textRotation: {
                    0: 0,
                    1: 45,
                    2: -45,
                    3: 'vertical',
                    4: 90,
                    5: -90,
                    default: 0
                }
            }

            let alignment = {
                vertical: luckyToExcel.vertical[vt],
                horizontal: luckyToExcel.horizontal[ht],
                wrapText: luckyToExcel.wrapText[tb],
                textRotation: luckyToExcel.textRotation[tr]
            }
            return alignment
        }

        var borderConvert = function (borderType, style = 1, color = '#000') {
            // 对应luckysheet的config中borderinfo的的参数
            if (!borderType) {
                return {}
            }
            const luckyToExcel = {
                type: {
                    'border-all': 'all',
                    'border-top': 'top',
                    'border-right': 'right',
                    'border-bottom': 'bottom',
                    'border-left': 'left',
                    'border-outside': 'outside',
                    'border-inside': 'inside',
                    'border-horizontal': 'horizontal',
                    'border-vertical': 'vertical',
                    'border-none': 'none',
                },
                style: {
                    0: 'none',
                    1: 'thin',
                    2: 'hair',
                    3: 'dotted',
                    4: 'dashDot', // 'Dashed',
                    5: 'dashDot',
                    6: 'dashDotDot',
                    7: 'double',
                    8: 'medium',
                    9: 'mediumDashed',
                    10: 'mediumDashDot',
                    11: 'mediumDashDotDot',
                    12: 'slantDashDot',
                    13: 'thick'
                }
            }
            let border = {}
            border[luckyToExcel.type[borderType]] = {
                style: luckyToExcel.style[style],
                color: { argb: color.replace('#', '') }
            }
            return border
        }

        function addborderToCell(borders, row_index, col_index) {
            let border = {}
            const luckyExcel = {
                type: {
                    l: 'left',
                    r: 'right',
                    b: 'bottom',
                    t: 'top'
                },
                style: {
                    0: 'none',
                    1: 'thin',
                    2: 'hair',
                    3: 'dotted',
                    4: 'dashDot', // 'Dashed',
                    5: 'dashDot',
                    6: 'dashDotDot',
                    7: 'double',
                    8: 'medium',
                    9: 'mediumDashed',
                    10: 'mediumDashDot',
                    11: 'mediumDashDotDot',
                    12: 'slantDashDot',
                    13: 'thick'
                }
            }
            // console.log('borders', borders)
            for (const bor in borders) {
                // console.log(bor)
                if (borders[bor].color.indexOf('rgb') === -1) {
                    border[luckyExcel.type[bor]] = {
                        style: luckyExcel.style[borders[bor].style],
                        color: { argb: borders[bor].color.replace('#', '') }
                    }
                } else {
                    border[luckyExcel.type[bor]] = {
                        style: luckyExcel.style[borders[bor].style],
                        color: { argb: borders[bor].color }
                    }
                }
            }

            return border
        }

        function createCellPos(n) {
            let ordA = 'A'.charCodeAt(0)

            let ordZ = 'Z'.charCodeAt(0)
            let len = ordZ - ordA + 1
            let s = ''
            while (n >= 0) {
                s = String.fromCharCode((n % len) + ordA) + s

                n = Math.floor(n / len) - 1
            }
            return s
        }

        //rgb(255,255,255)转16进制 #ffffff
        function colorRGBtoHex(color) {
            color = color.replace("rgb", "").replace("(", "").replace(")", "")
            var rgb = color.split(',');
            var r = parseInt(rgb[0]);
            var g = parseInt(rgb[1]);
            var b = parseInt(rgb[2]);
            return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
        }
    </script>
</body>

</html>

Node.js 接收前端上传文件的示例代码

首先,确保您已经安装了multer和express:

npm install multer express


然后,您可以使用以下代码来设置一个Express服务器,该服务器能够接收Blob格式的文件上传:

在项目一级目录,创建uploads文件夹和server.js

const express = require('express');
const multer = require('multer');
const app = express();

// 配置存储选项
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/'); // 保存的路径,确保这个目录存在
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname); // 使用原始文件名作为保存的文件名
  }
});

// 创建multer实例
const upload = multer({ storage: storage });

// 设置允许跨域请求,如果需要的话
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET, POST');
  next();
});

// 定义上传路由
app.post('/upload', upload.single('file'), (req, res) => {
  // req.file 包含了上传文件的信息
  if (!req.file) {
    return res.status(400).send('No file uploaded');
  }

  // 文件上传成功
  res.send(`File uploaded successfully. ${req.file.filename}`);
});

// 启动服务器
const port = 3000;
app.listen(port, () => {
  console.log(`Server running on port ${port}`);
});

启动服务

node server.js

参考内容:

1. Luckyexcel/README-zh.md

2.使用exceljs导出luckysheet表格

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1522413.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[游戏开发][UE5.3]GAS学习心得

GAS(GameplayAbilitySystem) UE提供的一套技能框架&#xff0c;这个框架也不是万能的&#xff0c;甚至各个部件你要进行封装开发&#xff0c;但这也比你从头写一套技能框架要容易很多。 GAS功能极其强大&#xff0c;所以它是一个庞大的系统&#xff0c;如果想运用得当&#x…

【刷题训练】牛客:JZ31 栈的压入、弹出序列

文章目录 一、题目要求二、解题思路三、C代码四、注意点五、运行成功 一、题目要求 二、解题思路 题意解读。本道题给定了两个序列pushV和popV&#xff0c;其中序列pushV是入栈顺序&#xff0c;popV是出栈顺序。问题就是让我们去判断这个popV的顺序是否可能是pushV的弹出顺序。…

瑞_Redis_短信登录(二)

文章目录 项目介绍1.1 项目准备1.2 基于Session实现登录流程1.2.1 发送短信验证码1.2.2 短信验证码登录、注册1.2.3 校验登录状态 1.3 实现发送短信验证码功能1.3.1 页面流程1.3.2 代码实现 1.41.51.6 &#x1f64a; 前言&#xff1a;本文章为瑞_系列专栏之《Redis》的实战篇的…

【LeetCode热题100】148. 排序链表(链表)

一.题目要求 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 二.题目难度 中等 三.输入样例 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输…

知名Web3投资基金a16z合伙人Jane Lippencott确认出席Hack.Summit() 2024区块链开发者大会

在区块链技术的风起云涌和Web3生态的蓬勃发展中&#xff0c;知名a16z Crypto的合伙人Jane Lippencott已确认出席即将于2024年4月9日至10日在香港数码港举行的Hack.Summit() 2024区块链开发者大会。作为亚洲首次举办的Hack.Summit()&#xff0c;此次大会将为全球区块链开发者及业…

DFS的一些题目

题目1&#xff1a;奶牛选美 这道题其实就是把两个连通块合成一个&#xff0c;可以用dfs、bfs和并查集。因为最近在dfs专题训练&#xff0c;这里我只写了dfs。 首先我们用dfs的方式遍历两个连通块&#xff0c;将两个连通块中点的坐标分别存入两个数组中&#xff0c;将这两个数组…

openssl3.2 - note - Writing OpenSSL Provider Skeleton

文章目录 openssl3.2 - note - Writing OpenSSL Provider Skeleton概述笔记测试工程的建立复现的provider工程总结Provider包含的头文件openssl/core.h中的数据结构实现 OSSL_provider_init()看一下openssl自带的提供者provider的openssl命令行测试provider的本质是hook了opens…

pytorch 入门基础知识一(Pytorch 01)

一 深度学习基础相关 深度学习三个主要的方向&#xff1a;计算机视觉&#xff0c;自然语言&#xff0c;语音识别。 机器学习核心组件&#xff1a;1 数据集(data)&#xff0c;2 前向传播的model(net)&#xff0c;3 目标函数(loss)&#xff0c; 4 调整模型参数和优化函数的算法…

【研发管理】产品经理-基础认知

导读&#xff1a;产品经理&#xff08;Product Manager&#xff09;是一个负责产品的全周期管理的职位&#xff0c;他们不仅参与产品的设计、开发、推广和销售&#xff0c;还涉及到产品的市场调研、用户需求分析、竞争分析、产品规划、产品测试以及后续的产品迭代等多个环节。产…

安装snap再安装flutter再安装localsend@Ubuntu(FreeBSD下未成功)

Localsend介绍 localsend是一个跨平台的文件传送软件&#xff0c;可以在Windows、MacOS、Linux、Android和IOS下互相传送文件&#xff0c;只要在同一个局域网即可。 localsend官网&#xff1a;LocalSend 尝试安装localsend&#xff0c;发现需要使用flutter&#xff0c; 安装f…

【AI】Ubuntu系统深度学习框架的神经网络图绘制

一、Graphviz 在Ubuntu上安装Graphviz&#xff0c;可以使用命令行工具apt进行安装。 安装Graphviz的步骤相对简单。打开终端&#xff0c;输入以下命令更新软件包列表&#xff1a;sudo apt update。之后&#xff0c;使用命令sudo apt install graphviz来安装Graphviz软件包。为…

挑战杯 机器视觉人体跌倒检测系统 - opencv python

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 机器视觉人体跌倒检测系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&…

前端之CSS 创建css--行内引入、内联样式、外联样式

创建css有三种创建样式&#xff0c;行内引入、内联引入、外联引入。 行内引入 在行内标签引入 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>行内样式</title> </head> <body>…

【安全类书籍-3】XSS跨站脚剖析与防御

目录 内容简介 作用 下载地址 内容简介 这本书涵盖以下几点: XSS攻击原理:解释XSS是如何利用Web应用未能有效过滤用户输入的缺陷,将恶意脚本注入到网页中,当其他用户访问时被执行,实现攻击者的目的,例如窃取用户会话凭证、实施钓鱼攻击等。 XSS分类:分为存储型XSS(…

单片机FLASH深度解析和编程实践(下)

本篇文章将同大家分享单片机FLASH编程的相关寄存器和寄存器操作及库函数操作。本篇文章依然以STM32单片机为例进行解析。有关FLASH的基本原理和实现方法&#xff0c;大家可以参考上一篇文章&#xff1a;单片机FLASH深度解析和编程实践&#xff08;上&#xff09;-CSDN博客 目录…

ChatGPT编程—实现小工具软件(文件查找和筛选)

ChatGPT编程—实现小工具软件(文件查找和筛选) 今天借助[小蜜蜂AI][https://zglg.work]网站的ChatGPT编程实现一个功能&#xff1a;根据特定需求结合通配符和其他条件来进行文件查找和筛选。在这个例子中&#xff0c;我们将创建一个函数find_files&#xff0c;它接受用户输入的…

solr/ES 分词插件Jcseg设置自定义词库

步骤&#xff1a; 1、找到配置文件jcseg-core/target/classes/jcseg.properties修改配置&#xff1a; 下载地址: https://gitee.com/lionsoul/jcseg#5-如何自定义使用词库 lexicon.path {jar.dir}/../custom-word 设置lexicon路径&#xff0c;我们这个配置可以自定义&#xf…

Java 与 Go:可变数组

可变数组&#xff08;也称为动态数组&#xff09;是一种可以在运行时动态增加或减少其大小的数据结构。由于其动态分配大小&#xff0c;灵活性增删改查&#xff0c;动态地管理内存&#xff08;在需要时动态分配内存空间&#xff0c;以适应数据结构的大小变化&#xff0c;而不会…

NCV1117ST50T3G线性稳压器芯片中文资料规格书PDF数据手册引脚图图片价格参数

产品概述&#xff1a; NCP1117系列为低压差&#xff08;LDO&#xff09;正向线性电压稳压器&#xff0c;能够提供超过1.0A的输出电流&#xff0c;800mA时温度范围内最大压差为1.2V。这一系列包括八个固定输出电压&#xff1a;1.5V、1.8V、2.0V、2.5V、2.85V、3.3V、5.0V 和 12…

​​SQLiteC/C++接口详细介绍之sqlite3类(十一)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;​​SQLiteC/C接口详细介绍之sqlite3类&#xff08;十&#xff09; 下一篇&#xff1a;​​SQLiteC/C接口详细介绍之sqlite3类&#xff08;十二&#xff09;&#xff08;未发表&#xff09; 33.sq…