bamboosnaketool v1.3.10
bamboosnaketool
快速上手 - 安装
npm install bamboosnaketool
// the github project url
https://github.com/liuyunqi/BambooSnake-ReactAntd
简单介绍
技术栈React + Antd-UI,内置常用的基础工具函数、通用组件、业务组件/函数。统一规范,减少重复开发提升交付质量效率,聚焦内容实现。
(如果为支持firefox-v5.0~5.3版,依赖antd的版本需锁死在v4.15.6,目前发现主要是table表格的支持,低版本position-Fixed会失效。)
推荐使用Typora的.md文档查看工具打开本地modules内的README.md文件,会有明确的模块目录分栏及内容段落,极大提高可读性。
基本依赖
import Bamboo, { enumDataMode as _enumDataMode } from 'bamboosnaketool';
import { Utiles, Components } from 'bamboosnaketool';
// 包含大量的工具函数 及 组件模块
const { AccessorOverdue, dateTransformer: _dateTransformer, CollectionElementCtrl, Table } = Bamboo;
const { Table: { default: KTTable } } = Components;
// 例: 转换日期 - 完整型
let xsdate = _dateTransformer(new Date(), _enumDataMode.FULL);
// 例:表格组件 - KTTable (可任意自定义模块名称)
<KTTable/>
工具函数/ 小工具合集
内置基本工具函数。
// Date对象 转换为 时间字符串(多种款)
dateTransformer = (dt: Date, viewMode?: enumDataMode): string
// 嵌套层级字符替换数据转换函数
/*
desc: 将对象数组数据进行无限递归转换,替换数据原字段为自定义字段。(且可选是否移除原字段数据)
@data: [{...}, ...], // 源数据
@tranConf: { // 转换字段配置
O:N, // 【O】:old,转换目标字段。【N】:new,更新的定义字段。
...
},
@options: // 相关配置
*/
recursionDataKeyNameTransform = <T>(data: T[], tranConf: recursionDataKeyTransformConf = { isChildrenKey: 'children' }, options: recursionDataKeyTransformOpt = {
needDeleteBefore: true
}): T[]
import Bamboo from 'bamboosnaketool';
const { dateTransformer, mergeUrl, ArrayVeidooTransfrom } = Bamboo;
// 日期转换器 - dateTransformer
dateTransformer = (dt: Date | number, viewMode?: enumDataMode): string;
// 路径合并, 去除拼接处 多或少的 '/'
mergeUrl = (arr: string[]): string;
// 一维数组转二维切割
ArrayVeidooTransfrom = (list: any[], mo: number) :array[];
RegExpValidator - 校验器
基本使用
针对{}对象进行校验。
import Bamboo from 'bamboosnaketool';
const { RegExpValidator, RegExpType } = Bamboo;
// 初始化配置
const creatValidtor = new Validtor({
regConfig: [
{
key: 'name',
type: RegExpType.CN,
name: '姓名',
require: true
}, {
key: 'phone',
type: RegExpType.PHONE,
name: '手机',
require: true
}, {
key: 'enCode',
type: RegExpType.EN,
name: '英文代号',
require: true
}
]
});
// 执行校验数据
let validResult = creatValidtor.exceValid({
name: '刘德华2',
phone: '18163741749',
enCode: 'code'
});
console.log(validResult);
// 验证结果 - 执行后的 console - validResult
{ // 如果 - 校验失败
validErrors: [
{
key: "name"
msg: "仅允许中文汉字"
name: "姓名"
require: true
type: 0
value: "刘德华2"
}
],
validPassState: false
}
{ // 如果 - 校验成功
validErrors: [],
validPassState: true
}
多项联合校验
支持多重联合校验,下例中分别写了CN/EN/PHONE,当然你甚至可以写更多;
// 初始化配置 - 多重联合校验
const creatValidtor = new Validtor({
regConfig: [
{
key: 'name',
type: [
RegExpType.CN,
RegExpType.EN,
RegExpType.PHONE
],
name: '姓名',
require: true
}
]
});
便捷调用
同时支持单数据快捷校验,无需实例化直接调用。
import Bamboo from 'bamboosnaketool';
const { RegExpValidator, RegExpType } = Bamboo;
// 单数据的便捷校验
let singleValid = Validtor.exceOnce('', RegExpType.CN); // 单项校验
let multiSingleValid = Validtor.exceOnce('', [ RegExpType.CN, RegExpType.IP]); // 多项校验
// 分别的打印结果
/* is singleValid
{
validErrors: "仅允许中文汉字"
validPassState: false
}
*/
/* is multiSingleValid
{
validErrors: {type: 'CN', msg: '仅允许中文汉字'},
{type: 'IP', msg: '必须是正确ip格式'}
validPassState: false
}
*/
配置项说明
可支持的内置校验类型。
// 校验单元格配置格式
interface RegExpValidatorConfItem {
key: string; // 关键key
type: RegExpType | RegExpType[]; // 校验内置类型
name: string; // 校验项名称
require?: boolean; // 是否必填
}
export enum RegExpType {
CN, // 中文
EN, // 英文字母
EN_NUMBER, // 任意英文+数字
DECIMAL, // 小数浮点数类型
INTEGER, // 整数类型 - 正负都可以
POSITIVE_INTEGER, // 整数类型 - 正数
UP_ZERO_INTEGER, // 0+正数 (<=0)
UP_ONE_INTEGER, // 1+正数 (<=1)
NUMBER, // 数字类型
EMAIL, // 电子邮箱
PHONE, // 手机 18165221849
TEL, // 电话 0731-5632575
PHONE_TEL, // 手机 + 电话
POSTCODE, // 邮政编码
HTTP, // http (支持 - :post,www,ip,http,https)
IP, // ip地址
IDENTITY_CARD, // 身份证
SYMBOL_CN, // 全角
SYMBOL_EN // 半角
}
返回格式
// 校验返回格式
interface RegExpValidatorErrorResponse {
validPassState: boolean; // 校验结果状态
validErrors: RegExpValidatorErrorItem[]; // 校验错误项集合
}
CollectionElementCtrl - HTML元素集合控制器
基本使用
针对元素对象集合进行遍历操作。
内置索引记录器,可以通过使用指令对其进行遍历,对遍历目标元素进行 Attr 属性赋值(如class、style),对非当前active元素进行清理值。
支持对目标元素进行class/ style的配置自定义。
import Bamboo from 'bamboosnaketool';
const { CollectionElementCtrl } = Bamboo;
// 元素集合操作
const $CollectionElementCtrl = new CollectionElementCtrl({
collectionsElements: [], // dom对象集合 (可初始化设置/ 通过.setCollectionsElements()插入调用)
indexRecord: 0, // 行索引 - rowIndex
columnIndex: 4, // 列索引 - 锁定单元格
needFoucusHTMLElementInput: true // 是否聚焦input - 是否需要检查当前 纵及列<td>单元格内是否包含input
});
组合使用
可结合 Bamboo.KeywordsContrl 的键盘事件组件搭配使用。(如:操作表格,通过键盘(上下左右)指令在表格的row及td中的元素进行操作。)
演示表格行通过 ↑ ↓ 键盘来做到行来回选中效果。
const TableScanRef = React.createRef<HTMLDivElement>(); // TABLE - 表格 (用于控制-rowSelected)
// 获取Element集合
const tbody = (TableRef.current as HTMLDivElement).children[0].querySelector('.ant-table-tbody');
let trNodes: HTMLTableRowElement[] = [];
tbody?.querySelectorAll('tr').forEach((trElement: HTMLTableRowElement, index: number) => {
if (index > 0) {
trNodes.push(trElement);
}
});
// 装载DOM元素集合到 组件内
$CollectionElementCtrl.setCollectionsElements(trNodes);
// print 是 Bamboo.KeywordsContrl 事件回调里的按键标识
if (print === 'top') {
$CollectionElementCtrl.reduce();
} else if (print === 'bottom') {
$CollectionElementCtrl.addition();
}
AccessorOverdue - 存取器 - 过期限制 (save data to localSession):
基本使用
让存储在 localStorage/ sessionStorage 的数据具备过期能力,满足一些需要数据失效的应用场景。
import Bamboo from 'bamboosnaketool';
const { AccessorOverdue } = Bamboo;
// 创建实例
const xAccessorOverdue = new AccessorOverdue({ // 过期存储
overdueTimeSecond: 3600 // 设置过期时间 - 单位-秒
});
/* 默认的配置 component default optiosn [可选]
{
projectAlias: 'baseToolAccessOverdue', // 命名空间
saveObject: accessOverdue_saveObjectEnum.sessionStorage, // 存储对象 'sessionStorage' | 'localStorage'
overdueTimeSecond: 60 // 过期时间 - 1 = 1s (单位/秒)
}
*/
// 写入存储
xAccessorOverdue.setItem('mockKey', {name: '我是需要保持的数据'});
// 提取存储
xAccessorOverdue.getItem('mockKey'); // 根据 [配置项-过期时间] 判断是否过期
xAccessorOverdue.getItem('mockKey', 1); // 根据本次形参 - 判断是否过期 (单位/秒 = 1s过期)
// 指定删除
xAccessorOverdue.removeItem('mockKey'); // 删除一项
xAccessorOverdue.removeItem(['mockKey', 'mockKey1', 'mockKey2']); // 删除多选
配置项中,projectAlias 有效防止命名冲突,saveObject可以指定存储的方式。
提取返回
不管isInvalid状态是否过期,数据永远是会保留返回。
// 执行 .getItem('mockKey')
{
isInvalid: boolean; // 是否已过期 - (true-无效已过期、false有效)
value: any; // setItem 之前存储的数据内容
}
配置项说明
// 配置props - options
export interface accessOverdue_defaultOption {
projectAlias?: string;
saveObject?: accessOverdue_saveObjectEnum;
overdueTimeSecond?: number;
}
export enum accessOverdue_saveObjectEnum {
sessionStorage = 'sessionStorage',
localStorage = 'localStorage'
}
// 实例可调用的api
{
setItem (key: string, data: any): void // 写入存储
getItem (key: string, overdueTimeSecond?: number): { isInvalid: boolean, value: { creatertime: number, value: any }} // 提取存储
removeItem (keys: string | string[]): void // 指定删除
}
Debounced / Throttle - 防抖/ 节流 (control event frequency):
防止高频触发、开销; 防抖 - 短暂时间内的多次执行,以最后一次执行为触发; 节流 - 一段周期内只执行一次;
import Bamboo from 'bamboosnaketool';
const { Debounced, Throttle } = Bamboo;
// 防抖 - 创建实例
const debounced = new Debounced().use((fn: Function) => {
typeof fn === 'function' && fn();
}, 500);
// 调用-防抖
debounced(() => {
// u can do any things...
});
// 实例可调用的api
{
/**
* @param func 需要包装的函数
* @param delay 延迟时间,单位ms
* @param immediate 是否默认执行一次(第一次不延迟)
*/
use = (func: Function, delay: number, immediate: boolean = false): Function
}
---------------------------[ 不华丽且低调的分割线 ]----------------------------------
// 节流 - 创建实例
const throttle = new Throttle().use((fn: Function) => {
typeof fn === 'function' && fn();
}, 500);
// 调用
destroy(); // 销毁
open(); // 开启
close(); // 关闭
{
/**
* @param func 需要包装的函数
* @param delay 延迟时间,单位ms
* @param immediate 是否默认执行一次(第一次不延迟)
*/
use = (func: Function, delay: number, immediate: boolean = false): Function
}
KeywordsContrl - 键盘事件捕捉器
方便快捷的获取按键捕捉及回调事件。
import Bamboo from 'bamboosnaketool';
const { KeywordsContrl } = Bamboo;
// 键盘事件
const $keywordsContrl = new KeywordsContrl();
// 按键事件回调
$keywordsContrl.allEventCallback = (eventName, data) => {
const { keyCode, print } = data;
// keyCode if enter -> 13
// print if up -> 'top | bottom | enter ... keywordsContrl_eventType'
}
// 事件类型定义
export enum keywordsContrl_eventType {
prev = 'prev',
next = 'next',
top = 'top',
right = 'right',
bottom = 'bottom',
left = 'left',
delete = 'delete',
enter = 'enter',
focus = 'focus',
blur = 'blur',
tableIsReady = 'tableIsReady',
init = 'init'
}
CreatTableHtmlElement - 打印模板表格
适用于生成表格相关的纸质打印单据。
此组件会很方便快速构造一个表格,并将数据渲染在表格内,有需要时可以达成纸质分页及各处自定义内容插槽(为了更符合单据的各种样式),同时支持尺寸自定义。
基本使用
下列示例仅根据 表头配置 + 数据 就能快速生成一个表格。
import { CreatTableHtmlElement } from 'bamboosnaketool';
// 配置表头 width 29.7cm
const printColumns = [
{
key: 'mainBarcode',
name: '条码',
width: 3
}, {
key: 'goodsName',
name: '品名、剂型号、规格、生产企业',
width: 5.5
}, {
key: 'permitHolder',
name: '上市许可持有人',
width: 3.7
}
];
// 模拟数据
const mockDatas = [
{ mainBarcode: '98500001', goodsName: '阿莫西林-5g*20/盒-江苏制药六厂', permitHolder: '刘备' },
{ mainBarcode: '98500002', goodsName: '云南白药牙膏250g/支-云南利民制药厂', permitHolder: '孙权' },
{ mainBarcode: '98500003', goodsName: '天然养生枸杞 500g/罐-六元堂股份药业', permitHolder: '曹操' },
// more...
];
let TABLEhtml = CreatTableHtmlElement(printColumns, mockDatas)();
可以自定义尺寸属性,如示例
let options = {
cssUnit: 'cm', // 内置默认是 'px',这里的单位会影响 printColumns[ item.width ]
... // ’欧佛阔斯‘,还有很多其他的属性
};
let TABLEhtml = CreatTableHtmlElement(printColumns, mockDatas, options)(/** 有需的话可配置插槽对象 **/);
插槽 Slot
该组件中插槽其实是满足打印需求非常关键的一个功能,因为很多实际应用场景下,需要打印的纸质单据并不是内容仅有表格,可能会有下列罗列情况:
1.打印多张,但第一张有个额外的小表格或一段前言声明之类的(那么第一张纸由于被其他内容占据可能表格被裁切高度只能有50%高,而后面其他页都是100%全高);
2.打印多张,需要在每一张都盖上 印章;
3.打印的每一张,内容表格的前后都需要添加一些内容(可能是一个元素结构,也可能是一段文本内容);
不再多举例,下面我们看看如何达成这些需求:
import { CreatTableHtmlElement, CreatTableHtmlElement_InnterSlotModeEnum } from 'bamboosnaketool';
// 复制一份上述示例,增加插槽内容演示
let TABLEhtml = CreatTableHtmlElement(printColumns, mockDatas, options)(
{
slotInner: [ // 表格集合组插槽 - 每个表格单元中的内容
{
mode: CreatTableHtmlElement_InnterSlotModeEnum.ONLY_FIRST_BEFORE,
HTMLtext: '仅第一个表格前方渲染的内容'
},
{
mode: CreatTableHtmlElement_InnterSlotModeEnum.ONLY_LAST_BEFORE,
HTMLtext: '仅最后一个表格的前方渲染的内容'
},
// has more...
],
// 表格集合组外部插槽
slotStamp: `<img src="${setimageDataUrl}" style="position: absolute; right: 1.5cm; bottom: 1.5cm; width: 4cm; height: 4cm;"/>`,
slotBefore: '开端xxx内容',
slotAfter: '落款xxxx内容',
});
打印单据示例
下面是一个带有表头的单据打印需求场景(由于无法上图)
import CreatTableHtmlElement, { CreatTableHtmlElement_InnterSlotModeEnum } from 'bamboosnaketool';
let setimageDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA......';
let title = {
billName: '大标题XXXXX单据',
storeName: '香樟东路门店',
billCode: '90000816',
shippingDate: '2021-10-21 19:58:23'
};
let deliveryHTMLtext = `
<div style="margin-bottom: 0.5cm;">
<h3 style="text-align: left; height: 0.8cm; line-height: 0.8cm;">${ title.billName }</h3>
<div style="display: flex;">
<div style="flex: 1;">
<span>收货门店:${title.storeName}</span>
</div>
<div style="flex: 1;">
<span>单据编号:${title.billCode}</span>
</div>
<div style="flex: 1;">
<span>开票日期:${title.shippingDate}</span>
</div>
</div>
</div>
`;
let TABLEhtml = CreatTableHtmlElement(printColumns, list.map(item => {
item['supplierState'] = '合格';
return item;
}), {
pageLimit: 14,
cssUnit: 'cm', // 单位 px/ pt/ cm...
pagerPhysicsWidth: '29.7cm',
tableHeight: '20.4cm',
tablePaddingTop: '1cm', // 内部padding-top
tablePaddingBottom: '1cm', // 内部padding-bottom
tableSpace: '0',
tableBorderWidth: '0.01cm',
tableTHPadding: '0.06cm',
tableTDPadding: '0.2cm 0.1cm',
tableFontSize: '0.2cm',
valueBoxHeight: '0.36cm', // 高度
// valueBoxMaxHeight: '0.72cm', // 最大高度
valueBoxMaxHeight: '1.08cm', // 最大高度
valueBoxLineHeight: '0.36cm', // 行高 h 1/2
valueBoxLineClamp: '2', // 最大显示行数
})({
slotInner: [{
mode: CreatTableHtmlElement_InnterSlotModeEnum.ONLY_FIRST_BEFORE,
HTMLtext: deliveryHTMLtext
}],
slotStamp: `<img src="${setimageDataUrl}" style="position: absolute; right: 1.5cm; bottom: 1.5cm; width: 4cm; height: 4cm;"/>`
});
打印应用
创建一个新窗口文档,将已生成好的表格插入。
// 打开弹窗打印执行
const openWindowPrint = (TITLE: string, HTMtext: string, options = {}) => {
try {
let wind = window.open('', '_blank');
(wind as Window).document.body.innerHTML = creatPrintDocumentWrapper(TITLE, HTMtext, options);
(wind as Window).print();
} catch (err) {
// 发生错误时进行交互提示
/*
Modal.error({
title: '发生错误',
content: '打开打印弹窗失败,当前游览器可能弹窗已被阻止,通过【设置 - 允许弹窗]】后再重试打印。'
});
*/
}
}
/**
* 新建文档包裹容器
* @param title 新建文档标题
* @param HTMLdom 新建文档元素内容
* @param options 配置项
*/
interface creatPrintDocumentWrapper_options {
htmlWidth?: string; // 文档整宽 (例:21cm)
page_sizeMode?: 'A4'; // 尺寸标准名
page_composeType?: 'landscape' | 'portrait'; // landscape 横版 / portrait 竖版
}
const creatPrintDocumentWrapper = (title: string = 'Print Document', HTMLdom: string, options: creatPrintDocumentWrapper_options = {}) => {
let defOpts: creatPrintDocumentWrapper_options = {
htmlWidth: '21cm', // 文档整宽
page_sizeMode: 'A4', // 尺寸标准名
page_composeType: 'portrait', // landscape 横版 / portrait 竖版
...options
};
return `
<!DOCTYPE html>
<html lang=\"en\">
<head>
<meta charset=\"UTF-8\">
<title>${ title }</title>
</head>
<style>
@page {
size: ${defOpts.page_sizeMode} ${defOpts.page_composeType};
}
* {
margin: 0;
padding: 0;
}
html {
width: ${defOpts.htmlWidth};
font-size: 0.3cm;
}
body {
margin: 0;
}
</style>
<body>
${ HTMLdom }
</body>
</html>
`;
}
结构关系
特别准备了这一部分,因为对组件构成的关系理解对使用组件到实际应用场景非常关键,由于用不了图片进行关系示意,所以相互结构关系的理解非常重要,我尝试将它说清楚一些。
我们先列出构成文档的参与者,按文档流的形式 由上至下。
[顶部插槽]start
[内容插槽组:
[
[第一个表格
[首个前]
[每个前]
[表格]
[每个后]
[首个后]
[印章]
],
[第二个表格(也许)
[每个前]
[表格]
[每个后]
[印章]
],
[ 也许中间有若干个表格 ....],
[最后一个表格
[末尾前]
[每个前]
[表格]
[每个后]
[末尾后]
[印章]
],
]
]
[底部插槽]end
上述假设了完整的配置结构组成了一个大篇幅,可能会存在分页,原则上每个页面内容在纵向填充是尽可能饱满(不浪费打印纸)。
分页情况:
首页会顶部插槽+第一个表格的组成;
中间的每个页面表格+前后填充饱满;
末尾页表格+底部插槽内容;
配置项说明
// 表格列配置
export interface CreatTableHtmlElement_columnsConf {
key: string,
name: string,
width?: string | number,
align?: string
}
// 每个单元表格 - 插槽配置 CreatTableHtmlElement_concatSlot.slotInner
interface CreatTableHtmlElement_slotInnerInter {
HTMLtext: string;
mode: CreatTableHtmlElement_InnterSlotModeEnum;
}
// 全插槽配置
export interface CreatTableHtmlElement_concatSlot {
slotBefore?: string; // 插入总结构的头始
slotAfter?: string; // 插入总结构内的末尾
slotStamp?: string; // 插入公章
slotInner?: [] | CreatTableHtmlElement_slotInnerInter[]; // 插入 table-item 内的具体位置
}
// 每个单元表格 - 插槽类型 slotInner集合的mode类型
export enum CreatTableHtmlElement_InnterSlotModeEnum { // 插入模式 - 可能插入多个或单个于 table-item DIV 中
ONLY_FIRST_BEFORE = 'ONLY_FIRST_BEFORE', // 仅首个 - 表格之前插入
ONLY_FIRST_AFTER = 'ONLY_FIRST_AFTER', // 仅首个 - 表格之后插入
ONLY_LAST_BEFORE = 'ONLY_LAST_BEFORE', // 仅末尾 - 表格之前插入
ONLY_LAST_AFTER = 'ONLY_LAST_AFTER', // 仅末尾 - 表格之后插入
EVERY_BEFORE = 'EVERY_BEFORE', // 每个之前
EVERY_AFTER = 'EVERY_AFTER', // 每个之后
UNDO = 'UNDO', // 无动作
};
// 组件配置项
export interface CreatTableHtmlElement_options {
pageLimit?: number; // 是否需要区别表格 - 数据总长度超出单页时将创建多个表格(便于打印)
cssUnit?: 'px' | 'pt' | 'cm'; // 尺寸单位,影响内部style配置及column.width
pagerPhysicsWidth?: string; // 纸张横向尺寸
tableHeight?: string; // 是否限制 - 单个表格容器高度
tablePaddingTop?: string; // 表格单元内边距 padding-top
tablePaddingBottom?: string; // 表格单元内边距 padding-bottom
tableSpace?: string; // 表格单元 margin-top
tableBorderColor?: string; // 表格边框色
tableBorderWidth?: string; // 表格边框线宽
tableZebraColor?: string; // 表头thead - 背景色
tableTHPadding?: string; // 表头thead - 内边距 padding
tableTDPadding?: string; // 表格td 内边距 padding
tableFontSize?: string; // 表格th、td - 字体大小
valueBoxHeight?: string; // 高度
valueBoxMaxHeight?: string; // 最大高度
valueBoxLineHeight?: string; // 行高 h 1/2
valueBoxLineClamp?: string; // 最大显示行数
}
公共组件
React、antd-UI
组件:
Table - 表格组件:(github - public)
内置pagination分页、支持表格列单元格自定义模板渲染、ACTIONS操作栏多功能渲染等;
目前表格使用 antd-UI ,表格组件封装了 Table-antd 和 Pagination-antd;
基本使用
// 使用bamboo表格组件
import Bamboo from 'bamboosnaketool';
const { Table: BamTable } = Bamboo;
return (
<BamTable dataSource={ dataSourceList } columns={ columns } rowKey={ 'id' } ALLEVENTCallback={ tableLLEVENTCallback }/>
)
lib - 页面模块组成
目前开发作者习惯性的文件方式搭配。假设有一个页面模块demoPage
src <
demoPage <
index.tsx; // 页面模块
index.less; // 页面样式
columns.ts; // 根据key生成的export对象,该对象符合 antd-column-item 及 结合组件内部封装的新属性
columns.d.ts; // key - tableCloumn 前端枚举 - 页面中如有用到关键字段推荐从这里统一使用
column - 列头配置
推荐方式为独立的 列头配置文件 和 列头.d。
基础的列头配置如下(类似antd的常规使用格式),如果是涉及到内置组件的后面会详细提及。
// 根目录
...,
mock,
pages --> homePage --> [ index.tsx, index.less, columns.ts, columns.d.ts ],
...otherlibs
// columns.ts
import { ColumnsType } from 'antd/es/table';
import { columnItemDecorator, Table_ColumnsTypeMine } from 'bamboosnaketool';
import { keys } from './columns.d';
// 字段配置
const originalConfMax = (
columnItemDecorator
)({
[keys.mainbarCode]: { name: '商品条码' },
[keys.goodCode]: { name: '商品编码' }
}, keys);
/*
originalConfMax = // 生成后的数据格式为:type is Object
{
mainbarCode:{
dataIndex: "mainbarCode",
key: "mainbarCode",
name: "商品条码",
title: "商品条码"
},
...
}
columnItemDecorator 是数据装饰的函数,通过编码人员简单的columnitem配置就能生产完整的数据,数据符合antd的api及bamboo组件封装props要求,且写少做多。
*/
// 将其导出
export const column_ALL: Table_ColumnsTypeMine = [
originalConfMax[keys.goodName],
originalConfMax[keys.mainbarCode]
];
// columns.d.ts
// ts 字段枚举配置
export enum keys {
mainbarCode = 'mainbarCode', // 商品条码
goodCode = 'goodCode', // 商品条码
...
}
columns.d.ts 的keys是枚举对象,键值对形式,其中【键】命名后不可更改,【值】则根据实际数据字段自由更改(建议项目中任何使用该字段时都引用 keys )。
这里之所以使用columns.ts和columns.d.ts构成方式,而不直接定义在index.tsx里是因为有以下几种应用情况:
keys 适用于导入提供其他相关模块引用,做到字段易维护统一;(比如页面的逻辑、mock模拟数据、等)
column.ts 内可通过函数生成单或多个配置内容,适用于某页面有多个tabs切换多表格场景;
columnItemDecorator 是执行 ’编译‘ 配置的关键函数,如涉及特殊情况需要在其他页面配置也是可以的,如下代码。
1.下面变量如 hasModelPredict, billRunStatus 可以是 useState/ Props,可以在任何地方嵌入任何变量作为条件进行逻辑约束;
2.condition 中使用了 evalString 方式,这种方式非常灵活,可以支持非常繁琐复杂的判断逻辑;
import { keys } from 'somePageModule';
import Bamboo, {
Table_ColumnCustomType, columnItemDecorator
} from 'bamboosnaketool';
const columnFactory = (
columnItemDecorator
)({
[keys.forecastCount]: {
name: '预测数量',
width: 80,
condition: [
// 条件满足 ->> 开启模型预测 + 且模型运行已完成 + 预测数量有值
`${Boolean(
(hasModelPredict && billRunStatus) &&
(
billRunStatus === ENUM_InitiativeBillRunModelStatus.MODEL_RUN_SUCCESS ||
billRunStatus === ENUM_InitiativeBillRunModelStatus.DELIVERY_CREAT_ING ||
billRunStatus === ENUM_InitiativeBillRunModelStatus.DELIVERY_CREAT_FAIL ||
billRunStatus === ENUM_InitiativeBillRunModelStatus.DELIVERY_CREAT_SUCCESS
)
)} && record['${[keys.forecastCount]}']!==undefined`,
{
customType: Table_ColumnCustomType.LINKBUTTON,
optionsApi: {
style: { width: 56 },
maxLength: 4
}
},
{ // 其实该处整个{}对象配置可以省略,组件内部会默认使用 NORMALRENDER 渲染正常文本显示。
customType: Table_ColumnCustomType.NORMALRENDER, // 默认渲染普通文本 - 该处可不设
}
]
}
});
let setOverColumns = columnCombo.map((icloum: any, index: number) => {
if (icloum.key === keys.forecastCount) {
return columnFactory[keys.forecastCount];
}
return icloum;
});
operation - 操作栏配置
(多功能配置ACTIONS)
操作栏支持多种可调配的交互操作方式,如下:
点击回调、点击模态框弹窗(Modal)、点击确认气泡框(Popconfirm)、隐藏、隐藏且占位、禁用锁定、仅某一条符合某条件、多渲染模式同时并存、仅图标、图标+文字、悬停是否显示title、仅图标锁定。
// 配置单个操作对象的大致包含
{
text: '查看明细', // 文本
eventType, // 事件交互方式
eventSubstance, // 对应各个eventType的不同格式配置
condition, // 显示方式
viewMode // 渲染方式
}
下面内容过于丰富,为便于理解,这里系统的归纳下:
事件交互方式:
{ ..., eventType: ? }
通过内置的枚举进行模式选择。(默认方式:CALLBACK)
对象 | 名称 | 说明 |
---|---|---|
Table_enumEventType.CALLBACK | 函数回调 | 触发会响应绑定的函数进行事件响应。 |
Table_enumEventType.MODALBOX | 模态框 | 可自定义模态框内容文本,并绑定弹窗 confrim/cancel 事件函数。 |
Table_enumEventType.POPCONFIRM | 气泡确认框 | 点击目标文字会在点击附近出现气泡确认框再次确认。功能与模态框类似可自定义文本内容及事件绑定。 |
物料:
{ ..., eventSubstance: ? }
配套对应不同 eventType , 配置完全不同;
对象 | 名称 | 配置格式 | 说明 |
---|---|---|---|
Table_enumEventType.CALLBACK | 函数回调 | ( record: any ) => void; | - |
Table_enumEventType.MODALBOX | 模态框 | { title: (string | JSX.html), content: (string | JSX.html), ok: Function, cancel: Function} | - |
Table_enumEventType.POPCONFIRM | 气泡确认框 | 与 模态框 一致。↑↑↑ | - |
显示方式:
{..., condition: { ?key: boolean | evalString }}
渲染条件允许配置多个,内含 { hide, transparent, locked }, 优先级按此序列;条件书写为 eval(string), 内置关键字为 'record';
对象 | 名称 | 优先级权重 | 说明 |
---|---|---|---|
hide | 隐藏 | 1(最高) | 条件成立则不显示,不干涉元素布局占位 |
transparent | 占位隐藏 | 2 | 条件成立则不显示,干涉元素布局占位 |
locked | 锁定 | 3 | 条件成立则禁用置灰 |
渲染方式:
{ ..., viewMode: ? }
渲染显示模式有三种,文字/ icon, { Table_enumViewMode.DEFAULT, Table_enumViewMode.ICON, Table_enumViewMode.ICONTEXT }。
对象 | 名称 | 说明 |
---|---|---|
Table_enumViewMode.DEFAULT | 默认 | 只显示文本 |
Table_enumViewMode.ICON | 仅图标 | 只显示自定义配置的图标 |
Table_enumViewMode.ICONTEXT | 图标兼文本 | 同时显示图标和文本的组合体 |
代码参考如下:
// tableMock.tsx
import { HomeOutlined } from '@ant-design/icons';
import { Table_enumEventType, Table_enumViewMode, Table_sActions as ActionInterface } from 'bamboosnaketool';
// 这是一个配置好的 操作栏 - ACTIONS
export const setActionsTestMock : ActionInterface[] = [
// 事件交互
{
text: '点击回调',
condition: {
hide: `['2', '3'].includes(record.key)`
},
eventType: Table_enumEventType.CALLBACK,
eventSubstance(record: RowProps) {
alert('can run xxx function event.');
}
}, {
text: '模态框',
condition: {
hide: `['2', '3'].includes(record.key)`
},
eventType: Table_enumEventType.MODALBOX,
eventSubstance: {
title: '模态框标题',
content: (
<div>
这是一段询问的内容,吧啦吧啦。。。
</div>),
ok(record) {
alert('ok')
},
cancel() {
alert('cancel')
}
}
}, {
text: '气泡确认框',
condition: {
hide: `['2', '3'].includes(record.key)`
},
eventType: Table_enumEventType.POPCONFIRM,
eventSubstance: {
title: '气泡标题',
content: '嗯哼?',
ok(record) {
alert('ok')
},
cancel() {
alert('cancel')
}
}
},
// 按鈕狀態
{
text: '隐藏且占位',
condition: {
transparent: `true`,
hide: `['1', '3'].includes(record.key)`
},
eventType: Table_enumEventType.CALLBACK,
eventSubstance(record: RowProps) {
alert('can run xxx function event.');
}
},
{
text: '显示图标',
icon: <HomeOutlined/>,
condition: {
hide: `['1', '2'].includes(record.key)`
},
eventType: Table_enumEventType.CALLBACK,
eventSubstance() {
},
viewMode: Table_enumViewMode.ICONTEXT
}
.... /* 还有非常多种 */
]
上述还有非常多种,具体可以参考 后期补全,示例文件删了
。(同时你可以使用该文件内的数据生成示例参考,datasource、columns、actions 都是齐全的)
eventType : 事件响应模式 { Table_enumEventType.CALLBACK, Table_enumEventType.MODALBOX, Table_enumEventType.POPCONFIRM };
eventSubstance : 配套对应不同 eventType , 配置完全不同;
condition : 渲染条件,内含 { hide, transparent, locked }, 优先级按此序列;条件书写为 eval(string), 内置关键字为 'record';
viewMode : 渲染显示模式,文字/ icon, { Table_enumViewMode.DEFAULT, Table_enumViewMode.ICON, Table_enumViewMode.ICONTEXT }。
将配置完成的 操作栏 数据与 column 数据进行数组合并。
import { setActionsTestMock } from '../tableMock.tsx';
import { ColumnRender_operationAction } from 'bamboosnaketool';
export const setColumns = [
{
title: '创建人',
dataIndex: 'str3',
key: 'str3',
},
{
title: '操作',
key: 'action',
render: (text: string, record: any, index: number) => {
let setActionsTest = setActionsTestMock;
// if 条件变更 setActions ...
return ColumnRender_operationAction(text, record, index, setActionsTest);
}
}
];
更多细节建议利用mock数据做一个例子,并花30分逐个尝试并理解为最佳。这里就没有逐一全部写清楚了。
column-Item - 配置定制化模板
支持表格单元格渲染,输入框类型、货币格式转换、时间戳转字符串、进度条(节状、直条、或任意款式)、高亮link内容等错综复杂的万象需求...,都可按照目前组件提供的内置模板模式达成。
配置示例:
// 这里就写局部结构,完整内容参考已上述过的【列头配置】
{
[keys.salesForecast]: {
name: '链接文本', // 其实这里是 列头名称,为方便理解这个改为了 ’示例模板名称‘
condition: [
'record.id !== "3"',
{
customType: Table_ColumnCustomType.LINKBUTTON,
customSettings: {
style: {
fontWeight: 'bold'
}
}
}
]
},
[keys.replenishNumber]: {
name: '输入框', // 其实这里是 列头名称,为方便理解这个改为了 ’示例模板名称‘
condition: [
'record.id !== "3"',
{
customType: Table_ColumnCustomType.INPUT,
optionsApi: {
style: { width: 56 },
maxLength: 4
}
},
{ // 其实该处整个{}对象配置可以省略,组件内部会默认使用 NORMALRENDER 渲染正常文本显示。
customType: Table_ColumnCustomType.NORMALRENDER, // 默认渲染普通文本 - 该处可不设
}
]
}
}
上述代码示例中出现了三个组件内置模板,Table_ColumnCustomType { LINKBUTTON, INPUT, NORMALRENDER }。
optionsApi 为antd-api,这里的设置参数全部是直接 setProps 到 antd-DOM 上的。根据不同的组件查看官方具体的api。 customSettings 设置一些自定义的dom属性,比如 customSettings.style, 这些最终也会以 setProps 方式应用到 DOM 的行间样式属性中;
为了方便理解,从概念上 optionsApi 可看作【setApis】,customSettings可看作【setPropertys】。
渲染条件 condition
这里condition(条件)要特别说下,它决定了每个列配置的最终渲染结果,根据条件满足与否执行A/ B;类似if else 无限递归
condition本身是数组,参考概念格式为 condition = boolean, A, B 或 boolean, A 。
c[0] 是布尔类型,成功则执行A,否则执行B;
A/B 是一个单个模板完整的配置方案;
B 非必填,不填时则渲染默认模板 Table_ColumnCustomType.NORMALRENDER(默认文本显示);
c[0]:书写可以是 true/ false/ 表达式, 或 eval(string),string数据关键字为 'record';
同时为满足相对复杂的业务需求,这里支持无限层级的类似 if else 嵌套,代码如下:
// 类似 if else 方式
{
name: '补货数量',
condition: [
true,
{
customType: Table_ColumnCustomType.INPUT,
optionsApi: {
style: { width: 56 },
maxLength: 4
}
},{
customType: Table_ColumnCustomType.TEXT,
optionsApi: {
style: { width: 56 },
maxLength: 4
}
}
]
}
// 伪代码理解
// [false, 3, [false, 5, [true, 18]]] - 结果:18
// [true, 996, [true, 42, [false, 23]]] - 结果:996
// [false, 5] - 结果:由于未设置B,则指向默认Table_ColumnCustomType.NORMALRENDER,或优先外部配置的 isItemRender
// 递归无限层级
{
name: '补货数量',
condition: [
true,
{
customType: Table_ColumnCustomType.INPUT,
optionsApi: {
style: { width: 56 },
maxLength: 4
}
},[
true,
{
customType: Table_ColumnCustomType.TEXT,
optionsApi: {
style: { width: 56 },
maxLength: 4
}
}, [ 无限层级... ]
]
]
}
模板 template
目前使用的模板都是内置的。在 ./template.tsx 中。 需要新增则需要扩展 Table_ColumnCustomType 类型名称 及 对应的 render 函数。
理想的最优解为之后迭代,让今后使用者能够外部定义追加扩展模板及模板类型名称。
表格事件 eventHandle
通过配置表格组件Props - ALLEVENTCallback, 传入一个方法,该方法仅会响应 template 模板事件。
// 全表格事件回调捕捉函数
const tableLLEVENTCallback: ALLEVENTCallbackType = (TYPE, data) => {
// 输入框 - 每次输入
if (TYPE === Enum_ALLEVENT.INPUT_onChange) {
const { e, record, columnItem, index } = data;
let key = columnItem.key;
let value = e.target.value;
//...
}
// 输入框 - 回车 / 失焦
else if (TYPE === Enum_ALLEVENT.INPUT_onPressEnter || TYPE === Enum_ALLEVENT.INPUT_onBlur) {
}
// 点击 预测销量
else if (TYPE === Enum_ALLEVENT.LINKBUTTON_onClick) {
// do anything...
}
}
顺便提一嘴,操作栏 ACTION 的事件回调函数为 eventSubstance。在配置 ACTION-item 时被一并配置,根据ACTION类型不同会有所不同。
Props Api
interface IProps {
dispatch: Dispatch;
columns: ColumnsType<ColumnsTypeMine>; // 表格列头
dataSource: any[]; // 表格数据
rowKey?: string | undefined; // 自定义关键参数 default: id
isShowPagination?: boolean; // 是否显示分页组件
defaultFirstPage?: number | undefined; // 默认开始页码
pageCurrent?: number | undefined; // 当前页码
pageTotal?: number | undefined; // 总页码数
pageLimit?: number | undefined; // 单页数据数量
pageSizeOptions?: string[] | undefined; // 单页数量变更
onPaginationChange?: ((page: number, pageSize: number) => void) | undefined; // 分页组件事件回调
onPaginationShowSizeChange?: ((current: number, size: number) => void) | undefined; // 是否显示分页组件
ALLEVENTCallback?: ALLEVENTCallbackType; // 公共回调函数 (可用于解决column-render组合任何组件的无限触发事件回调)
reloadApiTable?: TableProps<any>; // antd - table - api
reloadApiPagination?: PaginationProps; // antd - pagination- api
}
TS报错
参数声明 isItemRender 是 boolean, ColumnCustomType,但如果直接写成 isItemRender: true, ColumnCustomType.TEXTLINESINGLE,会造成props报错,原因是TS自动解析为 联合类型,而不是索引指定类型;
import Bamboo from 'bamboosnaketool';
const { Table: BamTable } = Bamboo;
// 这样指定个声明可以解决TS报错误识别问题
// 如不额外将 setIsItemRender 拿出来做TS会自动认为 [true, ColumnCustomType.TEXTLINESINGLE] 是 (boolean | ColumnCustomType)[],fuok!
const setIsItemRender: [boolean, ColumnCustomType] = [true, ColumnCustomType.TEXTLINESINGLE];
// table setProps - FAST
const setTableProps = {
dataSource: dataSourceList,
columns: saColumns,
isItemRender: setIsItemRender,
// isItemRender: [true, ColumnCustomType.TEXTLINESINGLE]
}
// render
<BamTable { ...setTableProps } />
解决其它含antd@type 的报错解决。页面调用时由于TS默认会识别 ‘small’ | ‘checkbox’ 为 string 类型。
import { SizeType } from 'antd/lib/config-provider/SizeContext.d';
import { RowSelectionType } from 'antd/lib/table/interface.d';
import Bamboo from 'bamboosnaketool';
const { Table: BamTable } = Bamboo;
const sizeType: SizeType = 'small';
const rowSelectionType: RowSelectionType = 'checkbox';
/* 或亦可如此,更爲简洁
{
size: ('small' as SizeType),
rowSelection: {
type: 'checkbox' as RowSelectionType
}
}
*/
// table setProps - FAST
const setTableProps = {
dataSource: dataSourceList,
columns: saColumns,
reloadApiTable: {
size: sizeType,
rowSelection: {
type: rowSelectionType,
onChange: (selectedRowKeys: React.Key[], selectedRows: any[]) => {
setCheckeds(prev => {
return [...selectedRowKeys]
});
},
getCheckboxProps: (record: any) => ({
// disabled: record.name === 'Disabled User', // Column configuration not to be checked
name: record.name,
}),
}
}
}
// render
<BamTable { ...setTableProps } />
TreeAbundant - 丰富的树组件 (Tabs + Tree):
使用antd的 tree + tabs 组件拼搭的封装组件。
基本使用
import Bamboo, { Components } from 'bamboosnaketool';
const { TreeAbundant, TreeAbundant_enumEVENTTYPE, TreeAbundant_eventHandle } = Bamboo;
// 丰富树组件 - 全事件回调
const treeAbundant_eventHandle: TreeAbundant_eventHandle = (TYPE, data) => {
if (TreeAbundant_enumEVENTTYPE.RADIO_CHANGE === TYPE) {
let value = data;
} else if (TreeAbundant_enumEVENTTYPE.TREE_CHECKED === TYPE) {
let { checkedKeysValue, checkedNodes } = data;
}
}
// 门店-丰富树props配置
const setTreeAbund = {
treeDataSource: storeTreeDatasource, // 树状嵌套数组数据
defaultTreeExpandedKeys: storeTreeDatasource.length > 0 ? [storeTreeDatasource[0].key] : [], // 默认展开yf首层级
effectTreeCheckedKeys: storeConfrimCodes, // array
isShowTabs: false, // 是否显示tabs
eventHandle: treeAbundant_eventHandle
};
// render ...
<TreeAbundant { ...setTreeAbund }/>
*为确保同步更新,effectTreeCheckedKeys必须始终配置,如果有没配置则填入空数组“[]”。
api参考
interface IProps {
dispatch: Dispatch;
treeDataSource: any[]; // tree组件数据
eventHandle: intfEventHandle; // 公共回调事件
effectTreeCheckedKeys: React.Key[]; // 再次定义多选 (default: 'key')
dataNodeKeyConf?: intfDataNodeKeyConf; // 关键字段自定义配置 [title, key, children]
isShowTabs?: boolean; // tab选项卡 - 是否显示
tabsItems?: intfTabsItem[]; // tab选项卡渲染数据 [{ label: string, value: string }, ...]
defaultRadioValue?: string; // 默认radioValue
defaultTreeExpandedKeys?: React.Key[]; // 设置默认展开 (default: 'key')
defaultTreeCheckedKeys?: React.Key[]; // 设置默认多选 (default: 'key')
defaultSelectedKeys?: React.Key[]; // 设置默认选中 (default: 'key')
treeOptiosApis?: TreeProps; // 树组件 apis - antd
mainStyle?: React.CSSProperties; // 主结构样式自定义
tabBoxStyle?: React.CSSProperties; // tab容器结构样式自定义
treeBoxStyle?: React.CSSProperties; // 树容器结构样式自定义
}
TableColumnsLayer - 表格列显示/隐藏组件
功能
- 动态变动表格列数据;
- 支持列数据存储/取赋值;
- 支持列数据拖动排序;
基本使用
- 给定表格列数据,此列数据需要可以变动
import Bamboo, { Utiles, Components } from 'bamboosnaketool';
import initColumn from './columns'; // 附属xx页面模块的表格配置
const { default: TableColumnsLayer } = Components;
const [ columns, setColumns ] = useState(initColumn); // 声明
// 定义列变动通知方法
const onColumnChange = (data:any, close:any) => {
// 选择的列数据
let { columns, width } = data;
// 如果操作列单独拿出来的,需要手动放进去
setColumns([...columns, ACTION_OPERATION]);
// 关闭列选择弹出窗
close();
}
// JSX中渲染注册触发事件按钮,及参数配置项
<TableColumnsLayer columns={ columns } onChange={ onColumnChange }>
<Button type="primary" ghost>
列选择
</Button>
</TableColumnsLayer>
配置项
配置项 | 类型 | 说明 | 默认值 |
---|---|---|---|
columns | 数组 | 表格的列数据 | 必填 |
onChange | 函数 | 回调函数,会回调给用户2个参数,一个data(包含columns和width),一个是关闭弹出窗口的方法 | 必填 |
table | ref | 默认插件会自己去找table,用户也可以传入table的ref,这样会更加准确 | 非必填 |
needStorage | 布尔值 | 是否存储此次操作的列数据,如果存储,下次进来会读取存储中的数据 | false |
注意事项
- 未传入ref,组件会自己去找,多个表格的情况有可能会出错,最好把表格的ref传入
- 如果操作列没有放到column,而是后面加入,那么回调方法中回调的列数据不包含操作列,需要手动把列数据放入,否则可能会出现操作列不见的情况
FileUploadExcelToData - 上传文件组件
内置生成一个button按钮,点击该按钮后弹窗windows-fileSelectWindow(windows系统自带文件选择窗口); 可以配置一些导入数量的相关数量限制tips阻断;
基本使用
import Bamboo, { Components, FileUploadExcelToData_callback } from 'bamboosnaketool';
const { FileUploadExcelToData } = Bamboo;
// 或 const { FileUploadExcelToData } = Components;
const excelAnaylsDataDispose: FileUploadExcelToData_callback = (
data,
options
) => {
const { file, onSuccess, onError } = options;
}
/*
import { UploadRequestOption } from 'rc-upload/lib/interface';
(
data: { jsonData: any[], excelColumns: string[] },
options: UploadRequestOption
) => any
*/
// 文件上传props
const fileExcelUploadProps = {
isLoading: isLoadingImportExcel,
isDisabled: isLockEdit,
buttonText: '上传文件',
singleUploadMaxLength: 100000,
slowMaybeMaxLength: 100000,
callback: excelAnaylsDataDispose,
uploadApiOptions: {
multiple: false,
maxCount: 1
},
buttonApiOptions: {
icon: <UploadOutlined />
}
};
// render...
<FileUploadExcelToData { ...fileExcelUploadProps } />
// 前置拦截功能待未来实现 (比如点击不是直接选择文件,而是判断条件)
功能
校验导入的文件类型MIME是否正确;
将导入文件的二进制类型转换为可读JSON数据对象;
对超出预设数量的导入操作进行拦截/提示;
自定义按钮;
配置项说明
配置项 | 类型 | 说明 | 默认值 | 必填 |
---|---|---|---|---|
isDisabled | boolean | 是否禁用 | false | 否 |
isLoading | boolean | 是否是载入状态 | false | 否 |
fileTypeStr | { override: boolean; // 是否覆盖 names: string[]; // 文件类型编码} | 文件类型编码,MIME | { false, [] } | 否 |
singleUploadMaxLength | number | 单次上传最大数量,超过限制时候会msg.warn + 逻辑阻断; | 3000 | 否 |
slowMaybeMaxLength | number | 执行时可能较慢提示,modal.confrim,确认后再执行 | 2000 | 否 |
buttonText | string | 按钮文本 | "导入" | 否 |
callback | function | null | 否 | |
uploadApiOptions | { ...antd-options } | antd-Upload,的相关再定义api。(不要覆盖customRequest) | {} | 否 |
buttonApiOptions | { ...antd-options } | antd-Button,的相关再定义api。 | { type: 'primary', ghost: true, title: '选择一份excel文件' } | 否 |
ImportFileExcelDataVerifyTool - Excel导入数据校验与转换
场景:想把excel的中文列头转成英文字段并且拿到转换后的数组,key是excel的列头中文,toKey是需要将原来的中文列头转成什么字段,type表示列值的类型,如果设置了type,那么转换后的数据类型会转成设置的type类型,类型枚举可使用ExcelType,目前包括的枚举(STRING, NUMBER, BOOLEAN, DATETIME, DATE, TIME, FLOAT)
基本使用
import Bamboo, { Utiles, Components } from 'bamboosnaketool';
const { ImportFileExcelDataVerifyTool } = Bamboo;
const { ExcelRule } = Utiles;
new importFileExcelDataVerifyTool({
file: ev.target.files[0], //file对象 必传
columns: [
{
key: "列名比如商品编码",
type: ExcelType.STRING, //数据类型,用于转换数据,具体类型可以查看ExcelType枚举
toKey: "把列头字段转换成的字段比如goodCode",
},
],
})
.valid() // 开始进行数据校验 必须有
.then((res)=>{
// 没有任何错误,将返回数据
// res 为 { total: 总行数, data: 数据数组 }
console.log(res);
})
设置预警值
场景:有限定用户excel数据量大小,并且需要告知用户数据量已经超出询问用户是否继续导入
import Bamboo, { Utiles, Components } from 'bamboosnaketool';
const { ImportFileExcelDataVerifyTool } = Bamboo;
const { ExcelRule } = Utiles;
new importFileExcelDataVerifyTool({
file: ev.target.files[0], //file对象 必传
columns: [
{
key: "列名比如商品编码",
type: 'string|number|boolean|float', //数据类型,用于转换数据
toKey: "把列头字段转换成的字段比如goodCode",
},
],
})
.warn((msg, confirm, cancel)=>{
//配置了warn字段必须加
// confirm() // 调用此函数表示继续操作
// cancel() // 此函数表示取消操作
})
.valid() // 开始进行数据校验 必须有
.then((res)=>{
// 没有任何错误,将返回数据
// res 为 { total: 总行数, data: 数据数组 }
console.log(res);
})
设置起始行
场景:需要从指定的excel行开始读取数据,可以设置startIndex配置,默认从第一行开始
import Bamboo, { Utiles, Components } from 'bamboosnaketool';
const { ImportFileExcelDataVerifyTool } = Bamboo;
const { ExcelRule } = Utiles;
importFileExcelDataVerifyTool({
startIndex:0, //开始行数
file: ev.target.files[0], //file对象 必传
columns: [
{
key: "列名比如商品编码",
},
],
})
.valid()
.then((res)=>{
// 没有任何错误,将返回数据
// res 为 { total: 总行数, data: 数据数组 }
console.log(res);
})
验证
场景:需要对上传的excel数据字段值进行校验,插件本身提供内置的验证,具体可使用插件暴露出的ExcelRule枚举查看,如果想要自己定义验证,可以使用ExcelRule.Customer,然后定义valid回调函数,回调函数会传入读取到的行数据(注:如果定义了转换的key,那么读取到的行数据中的列字段是经过转换的,不是excel显示的中文),回调函数如果返回true,表示验证通过,验证结束后,错误的验证消息会通过catch方法来进行捕捉,错误的消息可以通过配置msg字段来提示,如果不配置插件会使用自己定义的消息提示,一般来说如果使用了内置的验证会提示内置的验证提示,比如使用身份证号验证将默认提示xxx必须是身份证号,没有的内置验证将提示xxx格式错误
import Bamboo, { Utiles, Components } from 'bamboosnaketool';
const { ImportFileExcelDataVerifyTool } = Bamboo;
const { ExcelRule } = Utiles;
new importFileExcelDataVerifyTool({
file: ev.target.files[0], //file对象 必传
columns: [
{
key: "列名比如商品编码",
toKey: "把列头字段转换成的字段比如goodCode",
rules:[
{type:ExcelRule.CUSTOMER, valid:(row)=>{return row.goodCode=='a'}, msg:'自定义错误消息'}, //自定义校验
{type:ExcelRule.NUMBER, msg:'商品编码必须是数字'}, //使用内部校验规则 可以使用 ExcelRule枚举提供的校验规则
]
},
],
})
.valid() // 开始进行数据校验 必须有
.then((res)=>{
// 没有任何错误,将返回数据
// res 为 { total: 总行数, data: 数据数组 }
console.log(res);
}).catch((error)=>{
// 1.校验规则错误 2.interceptor设置的函数返回false
console.log(error); // {msg:}
})
手动添加数据
场景:1. 需要在行数据上添加字段 2. 想要遍历指定字段然后中断读取操作 可以使用interceptor方法,此方法会回调给用户行数据和验证过后的错误消息,此函数如果返回false则表示中断excel读取操作,如果返回false此函数会触发catch回调
new importFileExcelDataVerifyTool({
file: ev.target.files[0], //file对象 必传
columns: [
{
key: "列名比如商品编码",
type: 'string|number|boolean|float', //数据类型,用于转换数据
toKey: "把列头字段转换成的字段比如goodCode",
},
],
})
.interceptor((rowData:any, err:[])=>{
// 此方法不是必需要要有的,如果有数据转换或者要在行数据里面加些字段可以使用
// 使用interceptor来进行数据装换, data为行数据
rowData.field = Math.random();
console.log(rowData);
// return false直接中断操作抛出异常
return true;
})
.valid() // 开始进行数据校验 必须有
.then((res)=>{
// 没有任何错误,将返回数据
// res 为 { total: 总行数, data: 数据数组 }
console.log(res);
}).catch((error)=>{
// 1.校验规则错误 2.interceptor设置的函数返回false
console.log(error); // {msg:}
})
配置项说明
配置项 | 类型 | 说明 | 默认 |
---|---|---|---|
file | file对象 | file对象 | 必填 |
sheet | 数字 | excel中如果有多个工作簿,可以通过sheet配置项来配置读取第几个工作簿的数据 | 0 |
isDebugger | 布尔 | 是否显示警告在控制台中 | false |
mimeType | 数组 | 设置可以读取的文件类型,默认 | "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
max | 数字 | 最大行数 | 500 |
warn | 数字 | 预警行数 | 500 |
columns | 数组 | 配置excel列 | 必填 |
columns.key | 字符串 | 列名比如商品编码 | |
columns.type | ExcelType | 列名类型,描述此列数值的类型 | |
columns.toKey | 字符串 | 重命名key,比如key为商品编码,toKey为goodCode,那么导出的数据就是{goodCode:''}这种形式 | |
columns.rules | 数组 | rules:{type:ExcelRule.CUSTOMER, valid:(row)=>{return row.goodCode=='a'}, msg:'自定义错误消息'},{type:ExcelRule.NUMBER, msg:'商品编码必须是数字'} 注:msg可以为空,如果为空则会采用插件自带的提示 验证类型的可使用ExcelRule的枚举类型 |
方法说明
方法 | 说明 |
---|---|
valid | 校验方法,必须调用 |
warn | 配置了warn字段必须调用,会有三个参数回调给用户(msg, confirm, cancel) msg为消息,confirm为用户继续操作,cancel表示取消数据读取 |
interceptor | 此方法会回调给用户当前行数据和错误消息,如果用户在此方法中返回false,会中断读取数据操作,并且会调用catch抛出异常 |
then | 数据读取完成无错误会回调给用户一个对象,{ total: 总行数, data: 数据数组 } |
catch | 数据读取中如果有校验错误或者在intercepotor里返回false都会触发此方法,并回调给用户一个对象{type:'error', msg:'错误消息'} |
枚举类型
类型 | 说明 |
---|---|
ExcelRule | 内置规则枚举(NUMBER整数验证 MOBILE手机号验证 IDCARD身份证验证 NUMERIC小数验证 NOT_EMPTY非空验证 CUSTOMER自定义验证) |
ExcelType | 列类型枚举(STRING字符串 NUMBER整数数值包括负数 FLOAT小数 BOOLEAN布尔类型 DATETIME年月日时分秒格式 DATE年月日格式 TIME时分秒格式) |
FreeCustomRowLine - 增减行自由定义配置组件
支持能预先自由配置各种元素组合的单行模板(文字/ antd组件/ 自定义元素...)。 根据配置的单行模板,能够去生成n行该模板的独立数据控制,排序样式,单元素填值时的基础校验,最终生成表单数据。 同时支持单行的删除。(未来会支持 up down调序)。
基本使用
如下述示例,组成的是支持整单满[?]元,赠送[x?],[number?]
的设置项;
import Bamboo, { FreeCustomRowLine, FreeCustomRowLine_EVENTTYPE, FreeCustomRowLine_ELEMENTTEMP } from 'bamboosnaketool';
const { FreeCustomRowLine } = Bamboo;
// 配置增减行
const freeCustomRowLineConfProps = {
templateRow: [
{
elementTEMP: FreeCustomRowLine_ELEMENTTEMP.INNERHTML,
style: { width: 38, marginRight: 8 }
},
'整单满',
{
elementTEMP: FreeCustomRowLine_ELEMENTTEMP.INPUTNUMBER,
placeholder: '价格',
maxLength: 8,
style: { width: 100, marginLeft: 4, marginRight: 4 },
apiOptions: {
min: 0
}
},
'元,赠送',
{
elementTEMP: FreeCustomRowLine_ELEMENTTEMP.INPUT,
placeholder: '搜索商品',
maxLength: 10,
style: { width: 200, marginLeft: 4, marginRight: 4 }
},
',',
{
elementTEMP: FreeCustomRowLine_ELEMENTTEMP.INPUTNUMBER,
placeholder: '数量',
maxLength: 4,
style: { width: 90, marginLeft: 4, marginRight: 4 },
apiOptions: {
min: 0
}
}
],
callback: (TYPE: EVENTTYPE, data: any) => {
console.log(TYPE, data)
}
};
// render...
<FreeCustomRowLine {...freeCustomRowLineConfProps} />
如何简单理解上述呢?templateRow 是确定单行模板的如下:
// 支持类型
{
templateRow: [ string文本 | 内置模板对象 | JSX.Element ]
}
最终组件内部会平铺该数组内的所有内容组成完整的单行预模板;
初始化插入数据
支持通过数据对组件进行首次初始化的渲染生成。
下面的配置会初始化生成下列文本(由于无法附图,文字描述):
条件1:整单满 inputNumber 元,赠送 input-autocomplate ,数量 inputNumber 责任人 select,备注:input
import Bamboo, { FreeCustomRowLine_ELEMENTTEMP } from 'bamboosnaketool';
const __awardLineMockDatas = [
[
{ "value": `<span style="padding: 1px 5px; color: #fff; background-color: #FF7157; display: inline-block">类型</span>` },
{ "value": 128, disabled: true },
{
"value": "异步2",
"valueId": "async2",
"options": [
{ "value": "async1", "label": "异步1" },
{ "value": "async2", "label": "异步2" },
{ "value": "async3", "label": "异步3" }
]
},
{ "value": 1 },
{ "value": "选项1", "valueId": "a1" },
{ "value": "撒大大" }
]
];
// 配置增减行
const shoppingAwardGiftConfProps = {
datasource: __awardLineMockDatas,
templateRow: [
{
elementTEMP: FreeCustomRowLine_ELEMENTTEMP.INNERHTML,
style: { width: 38, marginRight: 8 }
},
'整单满',
{
stamp: 'PRICE',
elementTEMP: ELEMENTTEMP.INPUTNUMBER,
placeholder: '价格',
maxLength: 8,
style: { width: 100, marginLeft: 4, marginRight: 4 },
apiOptions: {
min: 0
}
},
'元,赠送',
{
stamp: 'SEARCH_GOODS',
elementTEMP: ELEMENTTEMP.AUTOCOMPLETE,
placeholder: '搜索商品',
maxLength: 10,
style: { width: 200, marginLeft: 4, marginRight: 4 }
},
',数量',
{
stamp: 'NUMBER',
elementTEMP: ELEMENTTEMP.INPUTNUMBER,
placeholder: '数量',
maxLength: 4,
style: { width: 90, marginLeft: 4, marginRight: 4 },
apiOptions: {
min: 0
}
},
'责任人',
{
stamp: 'PRINCIPAL',
elementTEMP: ELEMENTTEMP.SELECT,
placeholder: '选择性',
style: { width: 90, marginLeft: 4, marginRight: 4 },
options: [
{ value: 'fzr1', label: '吴亦凡' },
{ value: 'fzr2', label: '鹿晗' },
{ value: 'fzr3', label: '黄子韬' }
],
apiOptions: {}
},
',备注:',
{
stamp: 'REMARK',
elementTEMP: ELEMENTTEMP.INPUT,
placeholder: '请输入备注内容',
maxLength: 10,
style: { width: 200, marginLeft: 4, marginRight: 4 }
}
]
}
顶部按钮组
组件内置了顶部按钮组 ,该组可配置 新增一行、 重置、自定义;
其中 新增一行、 重置为内置,组件Props { showAddButton, showResetButton } 为 true 时显示,否则隐藏;
同时也支持配置多个自定义按钮,通过配置后可以更灵活的实现应用。
// 可通过配置属性 customManaButtons 实现
import Bamboo, { FreeCustomRowLine_ManaButton } from 'bamboosnaketool';
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons';
let freeCustomRowLineConfProps = {
...,
customManaButtons: [
{
text: '自定义按钮1',
type: FreeCustomRowLine_ManaButton.CUSTOM,
stamp: 'ANY_NAME_1',
style: {
color: 'red'
},
apiOptions: {
icon: <PlusOutlined/>
}
},
{
text: '自定义按钮2',
type: FreeCustomRowLine_ManaButton.CUSTOM,
stamp: 'ANY_NAME_2',
style: {
color: 'yellow'
},
apiOptions: {
icon: <DeleteOutlined/>
}
}
]
}
// render...
<FreeCustomRowLine {...freeCustomRowLineConfProps} />
// 事件响应回调 - 顶部按钮组
import Bamboo, { FreeCustomRowLine_ManaButtonProps } from 'bamboosnaketool';
let freeCustomRowLineConfProps = {
...,
buttonsCallback: (TYPE: FreeCustomRowLine_ManaButton, data?: Pick<FreeCustomRowLine_ManaButtonProps, 'stamp'>) => {
if (TYPE === FreeCustomRowLine_ManaButton.CUSTOM) {
// 这里使用配置的stamp值进行多个自定义按钮情况的区别
let stamp = data?.stamp;
// do somethings ...
}
}
};
选项的构成 - options
我们把配置项中 templateRow 里的每一个索引内容称之为 '单元'。
options配置合法字段使用 { value: any, label: string };
那么单元目前除String文本外,就都是antd的封装组件了,其中 autocomplate、selecet都会是涉及到多选的options选项,那么这个怎么配?
下拉选项首先我们分为两种 初始配置 和 异步设置 的,这两者带来的方式上也是不一样的,初始配置的只需配置一次覆盖所有生成行,异步设置的可以支持到 每一行的都不一样;
初始配置:适合固定的选择内容,比如每行都需要指定的选择 '负责人',而关联这次数据的的所有负责人池一共8人,那么原则上所有行的下拉负责人选项都可以是一致的;
异步配置:适合非固定选择内容,比如每行都需要模糊搜索到某个指定的内容,然后从模糊匹配到的下拉结果中选出一项,那么每一行最终选中的对象可能都不一致;
(!!!异步配置优先级高于初始配置,故异步配置动作是后置于初始配置,最终数据的渲染显示会是异步配置动作为准)
**初始配置
// 方式一 - 初始配置
const shoppingAwardGiftConfProps = {
templateRow: [
'选择责任人',
{
stamp: 'PRINCIPAL',
elementTEMP: ELEMENTTEMP.SELECT,
placeholder: '请选择负责人',
style: { width: 90, marginLeft: 4, marginRight: 4 },
options: [
{ value: 'fzr1', label: '吴亦凡' },
{ value: 'fzr2', label: '鹿晗' },
{ value: 'fzr3', label: '黄子韬' }
],
apiOptions: {}
}
],
// other - config
}
**异步配置
异步的数据插入是根据行的,需要在回调内进行插入。
下面模拟在INPUT框输入后,模拟请求获取XX数据,使用内置函数options进行插入。
(!!!函数 slotFn ,在部分回调事件中不存在,只在具体行被操作后的响应动作存在,这是一个闭包函数,内置包裹了当前操作的rowIndex行索引和rItemIndex单元索引,直接对其进行数据操作插入即可)
import { FreeCustomRowLine_EVENTTYPE, FreeCustomRowLine_callBackProps } from 'bamboosnaketool';
// 方式二 - 异步配置
const shoppingAwardGiftConfProps = {
templateRow: [
'选择商品',
{
stamp: 'SEARCH_GOODS',
elementTEMP: ELEMENTTEMP.AUTOCOMPLETE,
placeholder: '搜索商品',
maxLength: 10,
style: { width: 200, marginLeft: 4, marginRight: 4 }
}
],
callback: (TYPE: FreeCustomRowLine_EVENTTYPE, data: FreeCustomRowLine_callBackProps) => {
const { stamp, slotFn } = data;
if (TYPE === FreeCustomRowLine_EVENTTYPE.INPUT) {
if (stamp === 'SEARCH_GOODS') {
let arr = [
{ value: 'async1', label: '异步1'},
{ value: 'async2', label: '异步2'},
{ value: 'async3', label: '异步3'}
];
slotFn && slotFn({ options: arr });
}
}
}
// other - config
}
内置模板
演示内置模板单元的使用;
[
...,
{
elementTEMP: FreeCustomRowLine_ELEMENTTEMP.INPUTNUMBER,
placeholder: '数量',
maxLength: 4,
style: { width: 90, marginLeft: 4, marginRight: 4 },
apiOptions: {
min: 0
}
}
]
// 内置的模板 elementTEMP 作为它的type类型指定,可通过枚举 ELEMENTTEMP 来选取指定 (完整的单模板内容参考下面#完整参数类型)
// 目前支持 几种应用场景
// 普通输入框、纯数字输入框、支持搜索下拉的自动完成输入框、和普通文本SPAN标签元素,如下
enum FreeCustomRowLine_ELEMENTTEMP {
INPUT, // 输入框 - 普通
INPUTNUMBER, // 输入框 - 数字
AUTOCOMPLETE, // 输入框 - 自动完成
SELECT, // 下拉选择项
SPAN, // 文本内容
INNERHTML // 元素方式
}
// 根据对元素类型的规范理解使用 [placeholder/ maxLength/ value ];
// [style] 为通用类型,可对样式进行实际展示需要微调;
// apiOptions - 是antd的内置API支持,这些单元模板枚举完整的对应了antd的实际组件,具体可参考官方文档;
配置按钮
配置单行模板后缀(右侧)的控制按钮组。
支持删除一行,锁定一行(貌似没有需求会用到,暂未开发),向上移动一行,向下移动一行,
import { FreeCustomRowLine_LINEBUTTONS } from 'bamboosnaketool';
// 默认仅显示[删除]按钮,目前完整按钮包含4个 [ 删除/ 锁定行/ 向上移动/ 向下移动 ]
{
lineButtons: [
[ true, { type: FreeCustomRowLine_LINEBUTTONS.DELETE }],
[ false, { type: FreeCustomRowLine_LINEBUTTONS.LOCK }],
[ false, { type: FreeCustomRowLine_LINEBUTTONS.MOVE_UP }],
[ false, { type: FreeCustomRowLine_LINEBUTTONS.MOVE_DOWN }]
],
// ...
}
// 为 true 则显示反之隐藏,渲染顺序会根据当前配置内的数组排序为准
// 按钮会默认赋值内置的中文文本名称,也可以对text属性进行自定义,例↓:
[ true, { type: FreeCustomRowLine_LINEBUTTONS.DELETE, text: '剔除' }]
// 如需隐藏文本名称,可使用 hideText 配置如下:
[ true, { type: FreeCustomRowLine_LINEBUTTONS.DELETE, hideText: true }]
// 如何给按钮配置icon,且能同时结合 hideText 达到效果 (apiOptions - 参考antd组件api)
import { DeleteOutlined } from '@ant-design/icons';
[ true, { type: FreeCustomRowLine_LINEBUTTONS.DELETE, hideText: true, apiOtions: { icon: <DeleteOutlined>} }]
禁用
对单元进行禁用属性设置。(仅对支持disabled的对象有效)
方式有两种:渲染数据内 / 初始配置;
{ disabled: true }
回调响应
所有事件的响应都会callback统一抛出,可根据返回的行号几行内单元号进行具体的需求操作。
import { FreeCustomRowLine_callBackProps } from 'bamboosnaketool';
const freeCustomRowLineConfProps = {
templateRow: [
...
],
callback: (TYPE: FreeCustomRowLine_EVENTTYPE, data: FreeCustomRowLine_callBackProps) => {
const { allLineDatas, rowIndex, valIndex, value, slotFn?, prevAllLineDatas?, stamp? } = data;
console.log(TYPE, data);
}
};
// 回调响应事件类型
export enum FreeCustomRowLine_EVENTTYPE {
INIT ='INIT', // 初始化
INPUT = 'INPUT', // 输入响应
SELECT = 'SELECT', // 选中
ADD = 'ADD', // 新增一行
DELETE = 'DELETE', // 删除一行
FOCUS = 'FOCUS', // INPUT类型聚焦
BLUR = 'BLUR' // INPUT类型失焦
}
// 响应回调返回的data数据
data = {
allLineDatas, // 完整的数据
rowIndex, // 行的下标
valIndex, // 单行内的下标
value, // 响应 value / id
slotFn, // 行数据设置函数 - 闭包(直接设参,内置精确索引)
stamp // 印章 - 可用户多一种途径区别单元类型
}
完整参数类型
// 控件模板类型(antd)
export enum FreeCustomRowLine_ELEMENTTEMP {
INPUT, // 输入框 - 普通
INPUTNUMBER, // 输入框 - 数字
AUTOCOMPLETE, // 输入框 - 自动完成
SELECT, // 下拉选择项
SPAN, // 文本内容
INNERHTML // 元素方式
}
// 模板单item配置
export interface templateRowItemConf {
elementTEMP: FreeCustomRowLine_ELEMENTTEMP; // 模板类型
stamp?: string; // 印记 - 可用于回调事件做单元区别(多提供一种定位单元手动,处index定位外)
text?: string; // 文本
value?: string | number; // inputValue - 仅input [select/ input/ textarea/ ...]类型支持
options?: any[]; // select-options / autocomplate-options (仅支持antd - select/ autocomplate 组件)
disabled?: boolean; // 是否禁用该单元
style?: CSSStyleDeclaration | {}; // 样式
placeholder?: string; // 框内描述 - 仅input类型支持
maxLength?: string | number; // 最大输入长度 - 仅input类型支持
apiOptions?: {[x:string]: any} // antd-ui api
}
// 完整单行描述
export type templateRows = Array<templateRowItemConf | string | JSX.Element>
// 回调响应事件类型
export enum FreeCustomRowLine_EVENTT
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago