npm package: @qxg/excel
Description: ## 介绍
Author: WumaCOder
Latest version: 0.0.12

# @qxg/excel

## 介绍

是一个简单的进行解析和导出 excel 的库，支持图片和链接。

## 特性

- 支持多表导出
- 支持自定义读、写、下载文件的适配器
- 支持图片导出
- 自动展开 value 数组
- 自动识别多表

## 安装

```shell
npm i @qxg/excel
# yarn add @qxg/excel
# pnpm add @qxg/excel
```

## 使用

```ts
const { Excel } = require("@qxg/excel")

it('should export image excel array value', async () => {
  const writeFile = jest.fn((opt) => {
    fs.writeFileSync(opt.filePath, opt.data);
    return opt.filePath;
  });
  const excel = new Excel({
    download(opt: DownOpt): Promise<Buffer> {
      if (['png', 'jpg', 'jpeg', 'gif'].includes(opt.ext)) {
        let url = opt.url;
        if (!url.includes('imageMogr2')) {
          url += `?imageMogr2/thumbnail/300x300`;
        }
        console.log(url);

        return axios(url, { responseType: 'arraybuffer' }).then(
          (res) => res.data,
        );
      } else {
        return axios(opt.url, { responseType: 'arraybuffer' }).then(
          (res) => res.data,
        );
      }
    },
    async readFile(opt) {
      return new Promise((resolve, reject) => {
        fs.readFile(opt.filePath, (err, data) => {
          if (err) {
            reject(err);
          } else {
            resolve(data as any);
          }
        });
      });
    },
    writeFile(opt) {
      return writeFile(opt);
    },
  });

  expect(
    await excel.export(
      './test.xlsx',
      {
        表1: [
          {
            id: 1,
            name: '张三',
            age: 18,
            address: '北京市朝阳区',
            image: [
              'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
              'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
            ],
            image2: [
              'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
              'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
            ],
          },
          {
            id: 2,
            name: '李四',
            age: 18,
            address:
              '北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区北京市朝阳区',
            image: [
              'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
            ],
            image2: [
              'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
            ],
          },
          {
            id: 3,
            name: '李四',
            age: 18,
            address: '北京市朝阳区',
            image:
              'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
            image2:
              'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
          },
        ],
      },
      {
        embeddedImage: true,
      },
    ),
  ).toBe('./test.xlsx');
  expect(writeFile).toBeCalled();
});
```

> 更多例子：modules/@qxg/excel/src/excel.spec.ts

## API

### `method` *.export(fileName:string, jsonSheetData:any,exportOptions:ExportOption)=>string*

> 导出 Excel，详细请查看ts文件

fileName 是一个文件的名称

jsonSheetData 是传入的JSON或者JSON[]

```
{[sheetName as string]:Data[]} | Data[]
```

exportOptions 导出选项

```
export type ExportOptions = {
  engine?: 'xlsx' | 'exceljs'; // 默认引擎一般不需要设置
} & ExportEngineExcelJsOpt;

export type ExportEngineExcelJsOpt = {
  extOpts?: any; // 扩展参数，可以直接传入到适配器方法中
  embeddedImage?: boolean; // 是否嵌入图片
  rowHeight?: number; // 行高
  headerHeight?: number; // 表头高度
  headerWidth?: number; // 表头宽度
  defaultSheetName?: string; // 默认 sheet 名称
  notImageNarrow?: boolean; // 当没有图片的时候自动调整行高
  keyMap?: { [key: string | number]: string }; // 对象 key 对应的列名
};
```

### `method` *parse(filePath: string,sheetName: string | number, opts?: ParseOpt)=>Data[]*

> 解析Excel，详细请查看ts文件

filePath 文件地址，需要看适配器的支持情况

sheetName 读取的sheet名或下标

opts 解析选项

```
type Format = 'default' | 'table' | 'grid' | 'fields';

export type ParseOpt<F extends Format = Format> = {
  format?: F; // 解析格式
  fields?: string[]; // 解析字段
  sheetName?: string | number; // 解析sheet名
};

```



## 适配器接口

> 当进行扩展的时候需要写这块

```ts
export type WriteOpt = {
  filePath: string; // 文件路径
  data: any; // 写入的数据, 一般是Buffer
  extOpts?: any; // 扩展参数
};

export type ReadOpt = {
  filePath: string; // 文件路径
  extOpts?: any; // 扩展参数
};

export type DownOpt = {
  url: string; // 下载地址
  ext: string; // 扩展名
  extOpts?: any; // 扩展参数
};


export abstract class ExcelAdapter {
  abstract writeFile(opt: WriteOpt): Promise<string>;
  abstract readFile(opt: ReadOpt): Promise<Buffer>;
  abstract download(opt: DownOpt): Promise<Buffer>;
}
```

例子：

```ts
import axios from 'axios';
import { ExcelAdapter, DownOpt } from '@qxg/excel';

export class CosExcelAdapter extends ExcelAdapter {
  constructor(private cosService: CosService) {
    super();
  }

  download(opt: DownOpt): Promise<Buffer> {
    if (['png', 'jpg', 'jpeg', 'gif'].includes(opt.ext)) {
      let url = opt.url;
      if (!url.includes('imageMogr2')) {
        url += `?imageMogr2/thumbnail/300x300`;
      }
      return axios(url, { responseType: 'arraybuffer' }).then(
        (res) => res.data,
      );
    } else {
      return axios(opt.url, { responseType: 'arraybuffer' }).then(
        (res) => res.data,
      );
    }
  }

  readFile(opt) {
    return this.cosService.downloadCDNFile(opt.filePath);
  }
  writeFile(opt) {
    let name = opt.filePath;
    if (!name.startsWith('excel/')) {
      name = 'excel/' + name;
    }
    if (!name.endsWith('.xlsx') && !name.endsWith('.xls')) {
      name += '.xlsx';
    }

    name = name.replace(/\s+/gim, '_');

    return this.cosService.uploadFile(name, opt.data);
  }
}

```

这是一个COS的适配器，传入的fileName或在这里解析。



## 关于

MIT