0.11.1 • Published 7 months ago

@pluve/lego-excel-vue v0.11.1

Weekly downloads
-
License
MIT
Repository
-
Last release
7 months ago

@pluve/lego-excel-vue

乐高系列之 excel 文件处理

npm (scoped)

@pluve/lego-excel-vue 已经投入了我们的生产环境中使用,经受住了来自真实业务的考验,并伴随着我们的业务需求不断完善。

安装

# 依赖 vue@3.x/ant-design-vue@3.x/@ant-design/icons-vue@6.x
yarn add @pluve/lego-excel-vue

公共类型 LegoExcelTypes

LegoExcelTypes.TableKey

注意:0.10.0 版本以下为 ILegoExcelTableKey

导入数据对象描述

参数说明类型
label表头列名称string
value表头列属性(表头列名称所对应的 key)string
rules列规则校验Array<LegoExcelTypes.Rule>
formatter格式化该列数据(在解析excel时执行)(value?: string \| number) => any

LegoExcelTypes.Rule

注意:0.10.0 版本以下为 ILegoExcelRule

参数说明类型
required是否必填boolean
pattern正则校验RegExp
message错误提示string
validator自定义函数校验,syncValidateRulestrue 时返回 boolean,为 false 时返回 Promise<boolean>(value: any, rowData: { [key: string]: any }) => Promise<boolean> \| boolean0.10.0 版本以下不返回 rowData

LegoExcelTypes.ErrorModalOptions

注意:0.10.0 版本以下不返回。

export type ErrorModalOptions = Omit<ModalFuncProps, "content">;

LegoExcelImport

通常用于批量导入数据场景

API

参数说明类型默认值
title导入模态框标题string批量导入
btnText导入按钮文案string批量导入
templateUrl导入模版地址,优先级download > templateUrlstring-
download插槽,用于自定义下载导入模板v-slot:download-
tableKeys配置描述Array<LegoExcelTypes.TableKey>-
maxLength最大一次导入行数number-
fileSizeLimit文件大小限制(M)number-
beforeUploadStartbeforeUpload 前置校验(file: RcFile, FileList: RcFile[]) => Promise<boolean>-
beforeOk点击【确定】按钮前置校验(data: any[]) => Promise<boolean>-
customRequest自定义校验,一般用于业务校验(如调用后端接口校验)(data: any[]) => Promise<boolean>-
default默认插槽,用于自定义选择器 (调用 show 打开导入模态框)v-slot:default="{ show }"-
onFinish导入完成回调(data: any[]) => void-
onFileChange文件变化的事件(data: { file?: RcFile }) => void-
onCancel导入弹窗关闭事件-
modalProps透传 ant-design-vue Modal 组件属性interface ILegoExcelImportModalProps extends Omit<ModalProps, "onOk" \| "onCancel" \| "visible" \| "destroyOnClose" \| "closable" \| "keyboard" \| "maskClosable">;
uploadProps透传 ant-design-vue Upload 组件属性interface ILegoExcelImportUploadProps extends Omit<UploadProps, "accept" \| "fileList" \| "maxCount" \| "customRequest" \| "onRemove" \| "beforeUpload">;
readExcelOptionsXLSX.utils.sheet_to_json(worksheet: WorkSheet, opts?: Sheet2JSONOpts)中的第二个参数,0.10.0 版本以下不支持Sheet2JSONOpts-
errorModalOptionsLegoExcelUtils.showErrorByModal(errorList: string[], options: LegoExcelTypes.ErrorModalOptions \| number = 520) 中的第二个参数,0.10.0 版本以下不支持LegoExcelTypes.ErrorModalOptions-
syncValidateRules是否同步进行规则校验booleanfalse

校验顺序

  1. 上传时校验顺序:

    • beforeUploadStart 函数校验
    • 导入文件是否是 xlsx 格式
    • 导入文件大小是否超过 fileSizeLimit M
  2. 点击确定时校验顺序:

    • beforeOk 函数校验
    • 上传表格是否无数据
    • 表头校验
    • 最大限制一次导入 maxLength 条数据
    • 单元格必填等数据校验
    • 自定义校验

效果展示

demo 截图

使用示例

<template>
  <div :class="$style.wrap">
    <LegoExcelImport
      templateUrl="https://yf-test-oss.yifengx.com/webtest/pluve/static/lego-excel-import-file.xlsx"
      :tableKeys="CHANNEL_GOODS_TABLE"
      :fileSizeLimit="2"
      :customRequest="customRequest"
      @fileChange="onFileChange"
      @finish="onImportFinish"
      :error-modal-options="{ cancelText: '取消' }"
      :beforeUploadStart="beforeUploadStart"
      :beforeOk="beforeOk"
      :uploadProps="{ disabled: false }"
      :syncValidateRules="true"
    >
      <template #default="{ show }">
        <Button type="primary" @click="show">导入</Button>
      </template>
      <!-- <template #download>
        <Button type="link" size="small" style="padding: 0" @click="downloadTemplateUrl">自定义下载导入模板</Button>
      </template> -->
    </LegoExcelImport>
    <Button type="primary" @click="exportData" style="margin-left: 10px"
      >导出</Button
    >
  </div>
</template>

<script setup lang="ts">
import { Button } from "ant-design-vue";
import { isNumber, toNumber } from "lodash";
import { LegoExcelImport, LegoExcelUtils, LegoExcelTypes } from '@pluve/lego-excel-vue';

// excel单元格转为数字
const convertExcelCellToNumber = (value?: string | number) =>
  isNumber(value) ? value : !!value ? toNumber(value) : undefined;

const CHANNEL_GOODS_TABLE: LegoExcelTypes.TableKey[] = [
  {
    label: "*商品编码",
    value: "goodsCode",
    rules: [{ required: true, message: "请填写商品编码" }],
    formatter: (value) => `${value}`,
  },
  {
    label: "*商品名称",
    value: "goodsName",
    rules: [{ required: true, message: "请填写商品名称" }],
    formatter: (value) => `${value}`,
  },
  {
    label: "*供货价",
    value: "oldSaleAmount",
    rules: [
      { required: true, message: "请填写供货价" },
      {
        pattern:
          /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^0\.0[1-9])|(^0\.[1-9]([0-9])?$)/,
        message: "限制正两位小数",
      },
      {
        validator: (val) => {
          if (val > 999999999.99) {
            return false;
          }
          return true;
        },
        message: "供货价输入不合法",
      },
    ],
    formatter: convertExcelCellToNumber,
  },
  {
    label: "*上架状态",
    value: "isShelves",
    rules: [{ required: true, message: "请选择上架状态" }],
    formatter: (value) => `${value}`,
  },
];

const customRequest = (data: any[]) =>
    new Promise((resolve) => {
      // 模拟服务端校验
      setTimeout(() => {
        resolve(true);
      }, 500);
    });

const onImportFinish = (data: any[]) => {
  console.log("获取导入数据 --> ", data);
};

const onFileChange = (data: { file?: File }) => {
  console.log("监听文件变化 --> ", data.file);
};

const exportData = () => {
  const headers = [
    {
      key: "no",
      title: "序号",
    },
    {
      key: "name",
      title: "姓名",
    },
    {
      key: "age",
      title: "年龄",
    },
    {
      key: "desc",
      title: "描述",
    },
  ];
  const data = [
    {
      no: 1,
      name: "john",
      age: 12,
      desc: "我是一个随机的描述我是一个随机的描述我是一个随机的描述我是一个随机的描述",
    },
    {
      no: 2,
      name: "lucy",
      age: 19,
    },
  ];
  for (let index = 0; index < 10000; index++) {
    data.push({
      no: index + 3,
      name: Math.random() + "",
      age: Math.floor(Math.random() * 100),
      desc: Math.random() > 0.5 ? "开" : "关",
    });
  }
  LegoExcelUtils.exportExcel({
    headers,
    data,
    fileName: "测试导出.xlsx",
    colWidths: [{ wpx: 50 }, { wpx: 50 }, { wpx: 50 }, { wpx: 130 }],
  });
};

const downloadTemplateUrl = () => {
  LegoExcelUtils.exportExcel({
    headers: [
      {
        key: 'storeCode',
        title: '*门店编码',
      },
    ],
    data: [
      {
        storeCode: 'xxxx',
      },
    ],
    fileName: '通用门店导入模板.xlsx',
  });
};


const beforeUploadStart = async () => {
  console.log('1111');
  return true;
};

const beforeOk = async (data: any[]) => {
  console.log('获取导入数据 --> ', data);
  return true;
};
</script>

<style lang="less" module>
.wrap {
  position: relative;
  min-height: 52px;
  padding: 10px 10px 0;
  border-radius: 4px;
  margin-top: 10px;
}
</style>

LegoExcelUtils

提供一系列 Excel 相关方法

showErrorByModal

公用展示错误弹窗

Params

showErrorByModal(errorList, options)

参数说明类型默认值
errorList需要展示的错误信息string[]-
options错误弹窗 Modal 的额外 propsLegoExcelTypes.ErrorModalOptions \| number = 520-

示例

import { LegoExcelUtils } from '@pluve/lego-excel-vue';

const errorMessages = [{
  rowIndex: 1,
  message: '某某某不存在'
}];

LegoExcelUtils.showErrorByModal(
  errorMessages.map((item) => `第${item.rowIndex}行:${item.message}`),
  { cancelText: '取消' },
);

validateFields

用于读取到 Excel 数据后的校验(异步)。若 tableKeys 中的 rules 规则存在异步校验,则使用该方式。

Params

validateFields({ data, tableKeys })

参数说明类型默认值
data表格数据(不含表头)any[]-
tableKeys配置描述Array<LegoExcelTypes.TableKey>-

示例

import { LegoExcelUtils, LegoExcelTypes } from '@pluve/lego-excel-vue';

const result: {
  rowIndex: number; // 行数
  message: string; // 该行所有错误信息(多条以;分割)
}[] = await LegoExcelUtils.validateFields(params: {
  data: any[];
  tableKeys: LegoExcelTypes.TableKey[];
});

validateFieldsSync

用于读取到 Excel 数据后的校验(同步)。若 tableKeys 中的 rules 规则全为同步校验,则使用该方式。

Params

validateFieldsSync({ data, tableKeys })

参数说明类型默认值
data表格数据(不含表头)any[]-
tableKeys配置描述Array<LegoExcelTypes.TableKey>-

示例

import { LegoExcelUtils, LegoExcelTypes } from '@pluve/lego-excel-vue';

const result: {
  rowIndex: number; // 行数
  message: string; // 该行所有错误信息(多条以;分割)
}[] = LegoExcelUtils.validateFieldsSync(params: {
  data: any[];
  tableKeys: LegoExcelTypes.TableKey[];
});

readExcel

读取 Excel 文件

Params

readExcel({fileReaderRes, tableKeys, options})

参数说明类型默认值
fileReaderRes-any-
tableKeys配置描述Array<LegoExcelTypes.TableKey>-
optionsXLSX.utils.sheet_to_json(worksheet: WorkSheet, opts?: Sheet2JSONOpts)中的第二个参数Sheet2JSONOpts-

Result

参数说明类型默认值
data表格数据(不含表头)Array-
headers表头数据Array<String>-

示例

import { LegoExcelUtils } from '@pluve/lego-excel-vue';

const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onload = (e) => {
  const result = e.target?.result;
  if (!!result) {
    // 读取excel
    const excelRes = LegoExcelUtils.readExcel({
      fileReaderRes: result,
      tableKeys: tableKeys,
      options: { raw: true }, // 可选
    });
  }
};

exportExcel

前端导出 Excel 文件。

Params

exportExcel({headers, data, fileName, colWidths})

参数说明类型默认值
headersExcel 表头描述{ key: string; title: string; [key: string]: any; }[]-
data需要导出的数据any[]-
fileName导出 excel 的文件名string导出.xlsx
colWidths导出 excel 每一列宽度的集合{ wpx: number }[]-

注意:colWidths 未设置,则 exportExcel 方法中默认设置为 wpx 为 120,length 为 headers.length 的数组

示例

import { LegoExcelUtils } from '@pluve/lego-excel-vue';

const exportData = () => {
  const headers = [
    {
      key: "no",
      title: "序号",
    },
    {
      key: "name",
      title: "姓名",
    },
    {
      key: "age",
      title: "年龄",
    },
    {
      key: "desc",
      title: "描述",
    },
  ];
  const data = [
    {
      no: 1,
      name: "john",
      age: 12,
      desc: "我是一个随机的描述我是一个随机的描述我是一个随机的描述我是一个随机的描述",
    },
    {
      no: 2,
      name: "lucy",
      age: 19,
    },
  ];
  for (let index = 0; index < 10000; index++) {
    data.push({
      no: index + 3,
      name: Math.random() + "",
      age: Math.floor(Math.random() * 100),
      desc: Math.random() > 0.5 ? "开" : "关",
    });
  }
  LegoExcelUtils.exportExcel({
    headers,
    data,
    fileName: "测试导出.xlsx",
    colWidths: [{ wpx: 50 }, { wpx: 50 }, { wpx: 50 }, { wpx: 130 }],
  });
};

xlsx

xlsx

0.10.9

8 months ago

0.11.0

8 months ago

0.11.1

7 months ago

0.10.10

8 months ago

0.10.6

11 months ago

0.10.7

11 months ago

0.10.8

8 months ago

0.10.1

1 year ago

0.10.2

1 year ago

0.10.3

1 year ago

0.10.4

1 year ago

0.10.5

1 year ago

0.10.0

1 year ago

0.9.0

1 year ago

0.9.2

1 year ago

0.9.1

1 year ago

0.8.0

1 year ago

0.7.1

1 year ago

0.7.0

1 year ago

0.6.2

1 year ago

0.6.1

1 year ago

0.6.0

1 year ago

0.5.0

1 year ago

0.4.0

1 year ago

0.3.0

1 year ago

0.2.0

1 year ago

0.1.0

1 year ago

0.0.4

1 year ago

0.0.3

1 year ago

0.0.2

1 year ago

0.0.1

1 year ago