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

news/2024/7/21 7:03:15 标签: excel, html5, javascript

 

创建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.niftyadmin.cn/n/5437899.html

相关文章

类和对象 java 要点总结

# 类和对象 - 成员变量 有默认值0 - 成员方法 - 类名&#xff1a;大驼峰 - rename refactor 改类名 - new 实例化对象 - this 当前对象的引用 - this共有2种使用方式&#xff1a; - this.data 访问当前对象的实例成员变量 - this.func() 访问当前对象的实例成员方法 - t…

2733: 【搜索】【广度优先】 马遍历棋盘

题目描述 有一个n*m的棋盘(1<n,m<400)&#xff0c;在某个点上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步 输入 一行四个数据&#xff0c;棋盘的大小和马的坐标 输出 一个n*m的矩阵&#xff0c;代表马到达某个点最少要走几步&#xff08;左对齐&#…

2024智慧农场系统微信小程序前端如何上传以及配置

2024智慧农场系统微信小程序前端如何上传以及配置 首先下载微信开发者工具 下载好以后打开&#xff0c;然后导入项目 前端修改&#xff1a;siteinfo.js 里面的域名信息 改完之后开始在微信开发者工具中开发工具中编译、上传、发布即可

B005-springcloud alibaba 服务网关 Gateway

目录 网关简介Gateway简介Gateway快速入门基础版增强版简写版 Gateway概念及执行流程基本概念执行流程 断言Gateway内置路由断言内置路由断言工厂的使用 自定义路由断言工厂 过滤器过滤器简介局部过滤器内置局部过滤器自定义局部过滤器 全局过滤器内置全局过滤器自定义全局过滤…

【C++】手撕AVL树

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;能直接手撕AVL树。 > 毒鸡汤&#xff1a;放弃自…

2023年蓝桥杯模拟省赛——列名

目录 题目链接&#xff1a;2.列名 - 蓝桥云课 (lanqiao.cn) 思路 高级思路&#xff1a;进制转换 难点一 难点二 难点三 总结 题目链接&#xff1a;2.列名 - 蓝桥云课 (lanqiao.cn) 思路 先来看我的暴力的思路吧 主要有以下步骤&#xff1a; 初始化一个长度为3的数组res用…

【Hadoop】Hadoop概述与核心组件

目录 Hadoop概述Hadoop 发展历史Hadoop 三大发行版本1.Apache Hadoop&#xff08;常用&#xff09;2.Cloudera Hadoop3.Hortonworks Hadoop优势优势总结——4高&#xff08;高可靠、高扩展、高效、高容错&#xff09; Hadoop组成1.HDFS管理者&#xff1a;NameNode&#xff08;n…

Apache Dolphinscheduler - 无需重启 Master-Server 停止疯狂刷日志解决方案

记录的是一个 3.0 比较难搞的问题&#xff0c;相信不少使用过 3.0 的用户都遇到过 Master 服务中存在一些工作流或者任务流一直不停的死循环的问题&#xff0c;导致疯狂刷日志。不过本人到现在也没找到最关键的触发原因&#xff0c;只是看到一些连锁反应带来的结果…… 影响因素…