excel.js前端灵活导出数据,导出的单元格下拉选择,不可随意输入内容,固定列,加密等功能

要用到的2个包:
exceljs文档
FileSaver文档(用于保存文件下载)

基本导出案例:

const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('My Sheet');
// 设置列
worksheet.columns = [
    { header: 'Id', key: 'id', width: 10 },
    { header: 'Name', key: 'name', width: 32 },
    { header: 'D.O.B.', key: 'DOB', width: 10 }
];
// 插入数据
worksheet.addRow({ id: 1, name: 'John Doe', DOB: '2022-06-18' });
worksheet.addRow({ id: 2, name: 'Jane Doe', DOB: '2022-06-18' });
// 写入文件
const buffer = await workbook.xlsx.writeBuffer();
FileSaver.saveAs(new Blob([buffer]), `${formatMessage({ id: 'menu.LeaveManagement.WorkforceManagement' }) + '-' + filterDate}.xlsx`)

具体的灵活操作可以参考exceljs文档

如下图,导出后用户只能进行选择单元格值的功能,在文档中搜索 “数据验证”


image.png

image.png
具体案例

有不懂的可以复制属性在文档中搜索

// 导出
const exportExcel = async (selectedRows: any[]) => {
    const workbook = new ExcelJS.Workbook();  // 新建文档
    const worksheet = workbook.addWorksheet('Sheet1', {  //新建工作表
        views: [{ state: 'frozen', xSplit: 4, ySplit: 0 }], // 冻结视图:xSplit:冻结多少列
        properties: { defaultColWidth: 18 } // 默认列宽
    });

    // 列数据
    let _columns = [...columns, ...dateColumns];
    _columns = _columns.filter(item => (!item.hideInTable && item.dataIndex != 'index')).map(item => ({
        header: item.title,
        key: item.dataIndex
    }));
    worksheet.columns = [{  // 第一列增加可选班次对象,导入时对照出id用
        header: '可选班次对象',
        key: 'workShiftObj',
        hidden: true
    }, ..._columns];

    // 批量通过考勤组织id查询考勤班次
    let attendanceIds = selectedRows.map(item => item.attendance_org_id);
    attendanceIds = [...new Set(attendanceIds)];    // 去重
    const { data: workShifts } = await getWorkscheduleByIds(attendanceIds);
    // [{
    //     attendance_org_id: "***"
    //     id: "***"
    //     name: "B"
    //     tenant_id: "***"
    //     type: 1
    // }]

    // 数据
    let _selectedRows = JSON.parse(JSON.stringify(selectedRows));
    for (let i = 0; i < _selectedRows.length; i++) {
        for (let key in _selectedRows[i]) {
            if (_selectedRows[i][key].attendance_work_shift_name) {
                _selectedRows[i][key] = _selectedRows[i][key].attendance_work_shift_name;
            }
        }
        // 给第一列可选班次对象赋值
        _selectedRows[i].workShiftObj = workShifts.find((item: { attendance_org_id: string; }) => item.attendance_org_id == _selectedRows[i].attendance_org_id); // 考勤组织Id一致
    }
    worksheet.addRows(_selectedRows);  // 添加行数据

    // 遍历工作表中具有值的所有行
    worksheet.eachRow(function (row, rowNumber) {
        // 连续遍历所有非空单元格
        row.eachCell(function (cell, colNumber) {
            // console.log('Cell ' + rowNumber + '-' + colNumber + ' = ' + cell.value);
            if (rowNumber > 1 && colNumber > 4) {    // 标题不给范围 前3个列不给范围
                cell.dataValidation = {
                    type: 'list',
                    allowBlank: true, // 允许为空
                    showErrorMessage: true,
                    errorStyle: 'error',
                    formulae: [`"${workShifts.map((item: { name: string; }) => item.name).join(',')}"`]
                    // formulae: ['"One,Two,Three,Four"']
                };
                cell.protection = { locked: false };    // 锁定后 这些列可编辑,不设置的话整个文档都不可编辑了
            }
        });
    });
    // 锁定文档,防止用户操作不该操作的列
    await worksheet.protect('the/pass_word/danger', {
        selectLockedCells: false
    });
    // 写入文件导出
    const buffer = await workbook.xlsx.writeBuffer();
    FileSaver.saveAs(new Blob([buffer]), `${formatMessage({ id: 'menu.LeaveManagement.WorkforceManagement' }) + '-' + filterDate}.xlsx`)
};

导入

async function importExcel(file: Buffer) {
    const workbook = new ExcelJS.Workbook();  // new一下
    await workbook.xlsx.load(file);  // 读文件
    const worksheet = workbook.getWorksheet(1);  // 读sheet1
    const row2: any = worksheet.getRow(2);  // 读第二行数据
    row2.values.forEach((item: any) => {  // 处理第2行的数据
       
    });
    worksheet.eachRow(function (row, rowNumber) {  // 遍历行
        row.eachCell(function (cell, colNumber) {  // 遍历每一行的列
            cell.value  // 列值
        });
     });
}

ExcelJS只能读取buffer类型,所以需要用到文件转buffer
转buffer方法:

function getBuffer(file: File) {
    let reader = new FileReader();
    reader.readAsArrayBuffer(file);
    reader.onload = function (e: any) {
        try {
            let res = e.target.result; // ArrayBuffer
            let buf = Buffer.from(res); // Buffer
            importExcel(buf);
        } catch { }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,295评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,928评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,682评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,209评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,237评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,965评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,586评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,487评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,016评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,136评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,271评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,948评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,619评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,139评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,252评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,598评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,267评论 2 358

推荐阅读更多精彩内容