implement export csv

This commit is contained in:
AllenFang
2018-07-14 15:45:27 +08:00
parent 03ece4b1fc
commit f0e37b130c
12 changed files with 252 additions and 2 deletions

View File

@@ -0,0 +1,86 @@
/* eslint react/prop-types: 0 */
import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitContext, { CSVExport } from 'react-bootstrap-table2-toolkit';
import Code from 'components/common/code-block';
import { productsGenerator } from 'utils/common';
const products = productsGenerator();
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
const sourceCode = `\
import BootstrapTable from 'react-bootstrap-table-next';
import ToolkitContext, { Search } from 'react-bootstrap-table2-toolkit';
const { SearchBar, searchFactory } = Search;
const columns = [{
dataField: 'id',
text: 'Product ID'
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'price',
text: 'Product Price'
}];
<ToolkitContext.Provider
keyField="id"
data={ products }
columns={ columns }
>
<ToolkitContext.Consumer>
{
props => (
<div>
<h3>Input something at below input field:</h3>
<SearchBar { ...props.searchProps } />
<hr />
<BootstrapTable
{ ...props.baseProps }
search={ searchFactory({
...props.searchProps
}) }
/>
</div>
)
}
</ToolkitContext.Consumer>
</ToolkitContext.Provider>
`;
export default () => (
<div>
<ToolkitContext.Provider
keyField="id"
data={ products }
columns={ columns }
exportCSV
>
<ToolkitContext.Consumer>
{
props => (
<div>
<h3>Input something at below input field:</h3>
<CSVExport { ...props.csvProps } />
<hr />
<BootstrapTable { ...props.baseProps } />
</div>
)
}
</ToolkitContext.Consumer>
</ToolkitContext.Provider>
<Code>{ sourceCode }</Code>
</div>
);

View File

@@ -133,6 +133,9 @@ import FullyCustomSearch from 'examples/search/fully-custom-search';
import SearchFormattedData from 'examples/search/search-formatted';
import CustomSearchValue from 'examples/search/custom-search-value';
// CSV
import ExportCSV from 'examples/csv';
// loading overlay
import EmptyTableOverlay from 'examples/loading-overlay/empty-table-overlay';
import TableOverlay from 'examples/loading-overlay/table-overlay';
@@ -289,6 +292,9 @@ storiesOf('Table Search', module)
.add('Search Fromatted Value', () => <SearchFormattedData />)
.add('Custom Search Value', () => <CustomSearchValue />);
storiesOf('Export CSV', module)
.add('Basic Export CSV', () => <ExportCSV />);
storiesOf('EmptyTableOverlay', module)
.add('Empty Table Overlay', () => <EmptyTableOverlay />)
.add('Table Overlay', () => <TableOverlay />);

View File

@@ -1,12 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import statelessDrcorator from './statelessOp';
import createContext from './src/search/context';
const ToolkitContext = React.createContext();
class ToolkitProvider extends React.Component {
class ToolkitProvider extends statelessDrcorator(React.Component) {
static propTypes = {
keyField: PropTypes.string.isRequired,
data: PropTypes.array.isRequired,
@@ -17,11 +18,21 @@ class ToolkitProvider extends React.Component {
PropTypes.shape({
searchFormatted: PropTypes.bool
})
]),
exportCSV: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.shape({
fileName: PropTypes.string,
separator: PropTypes.string,
ignoreHeader: PropTypes.bool,
noAutoBOM: PropTypes.bool
})
])
}
static defaultProps = {
search: null
search: false,
exportCSV: false
}
constructor(props) {
@@ -53,6 +64,9 @@ class ToolkitProvider extends React.Component {
searchProps: {
onSearch: this.onSearch
},
csvProps: {
onExport: this.handleExportCSV
},
baseProps
} }
>

View File

@@ -4,3 +4,4 @@ import ToolkitProvider from './provider';
export default ToolkitProvider;
export const ToolkitContext = Context;
export { default as Search } from './src/search';
export { default as CSVExport } from './src/csv';

View File

@@ -43,5 +43,8 @@
"prop-types": "^15.0.0",
"react": "^16.3.0",
"react-dom": "^16.3.0"
},
"dependencies": {
"file-saver": "1.3.8"
}
}

View File

@@ -0,0 +1,33 @@
import React from 'react';
import PropTypes from 'prop-types';
const ExportCSVButton = (props) => {
const {
onExport,
children,
...rest
} = props;
return (
<button
type="button"
onClick={ onExport }
{ ...rest }
>
{ children }
</button>
);
};
ExportCSVButton.propTypes = {
children: PropTypes.node.isRequired,
onExport: PropTypes.func.isRequired,
className: PropTypes.string,
style: PropTypes.object
};
ExportCSVButton.defaultProps = {
className: 'react-bs-table-csv-btn btn btn-default',
style: {}
};
export default ExportCSVButton;

View File

@@ -0,0 +1,64 @@
/* eslint no-unneeded-ternary: 0 */
import FileSaver from 'file-saver';
export const getMetaInfo = columns =>
columns
.map(column => ({
field: column.dataField,
type: column.csvType || String,
formatter: column.csvFormatter,
formatExtraData: column.formatExtraData,
header: column.csvText || column.text,
export: column.csvExport === false ? false : true,
row: Number(column.row) || 0,
rowSpan: Number(column.rowSpan) || 1,
colSpan: Number(column.colSpan) || 1
}))
.filter(_ => _.export);
export const transform = (
data,
meta,
{
separator,
ignoreHeader
}
) => {
const visibleColumns = meta.filter(m => m.export);
let content = '';
// extract csv header
if (!ignoreHeader) {
content += visibleColumns.map(m => `"${m.header}"`).join(separator);
content += '\n';
}
// extract csv body
if (data.length === 0) return content;
content += data
.map((row, rowIndex) =>
visibleColumns.map((m) => {
let cellContent = row[m.field];
if (m.formatter) {
cellContent = m.formatter(cellContent, row, rowIndex, m.formatExtraData);
}
if (m.type === String) {
return `"${cellContent}"`;
}
return cellContent;
}).join(separator)).join('\n');
return content;
};
export const save = (
content,
{
noAutoBOM,
fileName
}
) => {
FileSaver.saveAs(
new Blob(['\ufeff', content], { type: 'text/plain;charset=utf-8' }),
fileName,
noAutoBOM
);
};

View File

@@ -0,0 +1,3 @@
import ExportCSVButton from './button';
export default { ExportCSVButton };

View File

@@ -0,0 +1,24 @@
import { getMetaInfo, transform, save } from '../csv/exporter';
const csvDefaultOptions = {
fileName: 'spreadsheet.csv',
separator: ',',
ignoreHeader: false,
noAutoBOM: true
};
export default Base =>
class CSVOperation extends Base {
handleExportCSV = () => {
const { columns, data, exportCSV } = this.props;
const meta = getMetaInfo(columns);
const options = exportCSV === true ?
csvDefaultOptions :
{
...csvDefaultOptions,
...exportCSV
};
const content = transform(data, meta, options);
save(content, options);
}
};

View File

@@ -0,0 +1,5 @@
import csvOperation from './csv';
export default {
csvOperation
};

View File

@@ -0,0 +1,4 @@
import Operation from './src/op';
export default Base =>
class StatelessOperation extends Operation.csvOperation(Base) {};

View File

@@ -0,0 +1,7 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
file-saver@1.3.8:
version "1.3.8"
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8"