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

 

创建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表格

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【嵌入式实践】【芝麻】【硬件篇-3】从0到1给电动车添加指纹锁:光耦+继电器电路设计及讲解

0. 前言 该项目是基于stm32F103和指纹模块做了一个通过指纹锁控制电动车的小工具。支持添加指纹、删除指纹&#xff0c;电动车进入P档等待时计时&#xff0c;计时超过5min则自动锁车&#xff0c;计时过程中按刹车可中断P档状态&#xff0c;同时中断锁车计时。改项目我称之为“芝…

Chapter 13 Techniques of Design-Oriented Analysis: The Feedback Theorem

Chapter 13 Techniques of Design-Oriented Analysis: The Feedback Theorem 从这一章开始讲负反馈Control系统和小信号建模. 13.2 The Feedback Theorem 首先介绍 Middlebrook’s Feedback Theorem 考虑下面负反馈系统 传输函数 Guo/ui G ( s ) u o u i G ∞ T 1 T G…

7.Java整合MongoDB—项目创建

整合MongoDB MongoDB的基本知识有所了解之后&#xff0c;我们开始着手上代码了&#xff0c;进来先来项目创建&#xff0c;如何引入mongodb&#xff0c;以及测试一下能否连接数据库。 1 新建springboot项目 其实只需要spring boot mongodb这个依赖就行&#xff0c;加那么多纯属…

sparksql简介

什么是sparksql sparksql是一个用来处理结构话数据的spark模块&#xff0c;它允许开发者便捷地使用sql语句的方式来处理数据&#xff1b;它是用来处理大规模结构化数据的分布式计算引擎&#xff0c;其他分布式计算引擎比较火的还有hive&#xff0c;map-reduce方式。 sparksql…

基于单片机的智能小车泊车系统设计

摘 要:随着信息技术的进步,汽车逐渐朝着安全、智能方向发展,智能泊车系统的出现不仅能帮助人们更加快速、安全地完成泊车操作,而且适用于狭小空间的泊车操作,降低驾驶员泊车负担,减轻泊车交通事故发生率。文章基于单片机设计自动泊车系统,以单片机为核心来实现信息收集及…

文件系统I/O FATFS RW 源码分析

文件系统I/O FATFS RW 源码分析 0 参考 FatFs 是用于小型嵌入式系统的通用 FAT/exFAT 文件系统模块。FatFs 整个项目都按照 ANSI C (C89) 编写。与存储器 I/O 解耦良好&#xff0c;便于移植到 8051、PIC、AVR、ARM、Z80、RX 等小型微控制器中。 下面是关于 FAT 文件系统格式…

【Exception系列】SocketTimeoutException

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

ADO .Net操作SQL Server数据库

//ADO.NET是.NET Framework提供的数据访问服务的类库&#xff0c;应用程序可以使用ADO.NET连接到这些数据源&#xff0c;并检索、处理和更新数据 //常用的数据源包括四种&#xff1a;&#xff08;1&#xff09;Microsoft SQL Server数据源&#xff1a;使用System.Data.SqlClien…

STM32---SG90舵机控制(HAL库,含源码)

写在前面&#xff1a;在嵌入式的项目中&#xff0c;舵机是一个十分常见的元器件模块&#xff0c;其主要的功能是实现机械转动&#xff0c;实质上舵机是一个伺服的驱动器&#xff0c;适用于那些需要角度不断变化并可以保持的控制系统。例如在机器人的电控制器系统中&#xff0c;…

Java8中Stream流API最佳实践Lambda表达式使用示例

文章目录 一、创建流二、中间操作和收集操作筛选 filter去重distinct截取跳过映射合并多个流是否匹配任一元素&#xff1a;anyMatch是否匹配所有元素&#xff1a;allMatch是否未匹配所有元素&#xff1a;noneMatch获取任一元素findAny获取第一个元素findFirst归约数值流的使用中…

在线BLOG网|基于springboot框架+ Mysql+Java+JSP技术的在线BLOG网设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 管理员功能登录前台功能效果图 系统功能设计 数据库E-R图设计 lunwen参考 摘要 研究…

C语言学习过程总结(18)——指针(6)

一、数组指针变量 在上一节中我们提到了&#xff0c;指针数组的存放指针的数组&#xff0c;那数组指针变量是什么呢&#xff1f; 显而易见&#xff0c;数组指针变量是指针 同样类比整型指针变量和字符指针变量里面分别存放的是整型变量地址和字符变量地址&#xff0c;我们可以…

每周AI新闻(2024年第11周)Meta公布Llama 3集群细节 | Sora将于年内推出 | 全球首个AI软件工程师发布

这里是陌小北&#xff0c;一个正在研究硅基生命的碳基生命。正在努力成为写代码的里面背诗最多的&#xff0c;背诗的里面最会写段子的&#xff0c;写段子的里面代码写得最好的…厨子。 每周日解读每周AI大事件。 欢迎关注同名公众号【陌北有棵树】&#xff0c;关注AI最新技术…

第二十四天-数据可视化Matplotlib

目录 1.介绍 2.使用 1. 安装&#xff1a; 2.创建简单图表 3.图表类型 1.一共分为7类 2.变化 1.折线图 3.分布 ​编辑 1.直方图 2.箱型图 4.关联 1. 散点图&#xff1a; 2.热力图&#xff1a; 5.组成 1.饼图 2.条形图 6.分组 1.簇型散点图 2.分组条形图 3.分…

【ollama】linux、window系统更改模型存放位置,全网首发2024!

首先是window系统 so easy 直接进入系统环境变量添加就行 其次是linux系统 全靠自己试出来的,去Ollama官网找半天文档不知道在哪,而且linux也没有说:【 https://github.com/ollama/ollama/blob/main/docs/README.md https://github.com/ollama/ollama/blob/main/docs/li…

Ubuntu 如何安装 Beyond Compare?

Ubuntu20.04安装Beyond Compare 4.3.7 一、官网下载方式一&#xff1a;方法二&#xff1a;使用 .deb 包安装 二、安装相关依赖和bcompare三、破解常见错误解决方法 ) 文件比较工具Beyond Compare是一套由Scooter Software推出的文件比较工具。主要用途是对比两个文件夹或者文件…

HCIA——30奈奎斯特定理、香农定理

学习目标&#xff1a; 计算机网络 1.掌握计算机网络的基本概念、基本原理和基本方法。 2.掌握计算机网络的体系结构和典型网络协议&#xff0c;了解典型网络设备的组成和特点&#xff0c;理解典型网络设备的工作原理。 3.能够运用计算机网络的基本概念、基本原理和基本方法进行…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:TextTimer)

通过文本显示计时信息并控制其计时器状态的组件。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口 TextTimer(options?: TextTimerOptions) 参数&#xff1a; 参数名参数类型…

Kotlin进阶之协程从入门到放弃

公众号「稀有猿诉」 原文链接 Kotlin进阶之协程从入门到放弃 协程Coroutine是最新式的并发编程范式&#xff0c;它是纯编程语言层面的东西&#xff0c;不受制于操作系统&#xff0c;轻量级&#xff0c;易于控制&#xff0c;结构严谨&#xff0c;不易出错&#xff0c;易于…

深入浅出理解 AI 生图模型

目录 引言 一、Stable Diffusion原理 首先 随后 最后 二、DDPM模型 1 资料 2 原理 扩散过程 反向过程 3 公式结论 三、优缺点 优点&#xff1a; 缺点&#xff1a; 四、改进与完事 LDM代表作 原理概括 Latent Space&#xff08;潜空间&#xff09; 五、总结 引…