You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
5.3 KiB
JavaScript
148 lines
5.3 KiB
JavaScript
import React, { useState, useEffect } from "react";
|
|
import { Tag, Button, message } from 'antd';
|
|
import { CaretUpOutlined, CaretDownOutlined, DownloadOutlined } from '@ant-design/icons';
|
|
import { utils, writeFile } from "xlsx";
|
|
import { isEmpty, getNestedValue, fixTo2Decimals } from "@haina/utils-commons";
|
|
|
|
/**
|
|
* @property diffPercent
|
|
* @property diffData
|
|
* @property data1
|
|
* @property data2
|
|
*/
|
|
export const VSTag = (props) => {
|
|
const { diffPercent, diffData, data1, data2 } = props;
|
|
const CaretIcon = parseInt(diffPercent) < 0 ? CaretDownOutlined : CaretUpOutlined;
|
|
const tagColor = parseInt(diffPercent) < 0 ? 'gold' : 'lime';
|
|
return parseInt(diffPercent) === 0 ? (
|
|
'-'
|
|
) : (
|
|
<span>
|
|
{/* <div>
|
|
{data1} vs {data2}
|
|
</div> */}
|
|
<Tag icon={<CaretIcon />} color={tagColor}>
|
|
{diffPercent}<span>%</span>{' '}<span>{diffData}</span>
|
|
</Tag>
|
|
</span>
|
|
);
|
|
};
|
|
|
|
/**
|
|
* @property {number} [diffPercent=0]
|
|
* @property {number} diffData
|
|
* @property {number} data1
|
|
* @property {number} data2
|
|
* @property {string} dataSuffix
|
|
*/
|
|
export const VSDataTag = ({ diffPercent=0, diffData=0, data1=0, data2=0, dataSuffix='' }) => {
|
|
const _diffPercent = diffPercent || ((data2) ? fixTo2Decimals((data1-data2)/data2*100) : 100);
|
|
const _diffPercentSuffix = String(_diffPercent).includes('%') ? '' : '%';
|
|
const _diffData = diffData || (isNaN(data2) ? fixTo2Decimals(data1-0) : (fixTo2Decimals(data1-data2)));
|
|
const CaretIcon = parseInt(_diffPercent) < 0 ? CaretDownOutlined : CaretUpOutlined;
|
|
const tagColor = parseInt(_diffPercent) < 0 ? 'gold' : 'lime';
|
|
// parseInt(_diffPercent) === 0 ? (
|
|
// '-'
|
|
// ) :
|
|
return (
|
|
<span>
|
|
<div>
|
|
{data1}{dataSuffix} <b>VS</b> {data2}{dataSuffix}
|
|
</div>
|
|
{_diffData !== 0 && (
|
|
<Tag icon={<CaretIcon />} color={tagColor}>
|
|
{_diffPercent}<span>{_diffPercentSuffix}</span> <span>{_diffData}{dataSuffix}</span>
|
|
</Tag>
|
|
)}
|
|
</span>
|
|
);
|
|
};
|
|
|
|
/**
|
|
* 表格中显示数据对比
|
|
*
|
|
* @property {boolean | undefined} [showDiffData=false]
|
|
* @property {number} [diffPercent=0]
|
|
* @property {number} diffData
|
|
* @property {number} data1
|
|
* @property {number} data2
|
|
* @property {string} dataSuffix
|
|
*/
|
|
export const RenderVSDataCell = ({ showDiffData=false, data1=0, data2=0, dataSuffix = '', ...props }) => {
|
|
if (showDiffData) {
|
|
return <VSDataTag data1={data1} data2={data2} dataSuffix={dataSuffix} {...props} />;
|
|
}
|
|
return <div>{data1}{dataSuffix}</div>;
|
|
};
|
|
|
|
/**
|
|
* 导出表格数据存为xlsx
|
|
* @property label 文件名字
|
|
* @property columns 表格列
|
|
* @property dataSource 表格数据
|
|
* @property btnTxt 按钮文字
|
|
*/
|
|
export const TableExportBtn = ({label, columns, dataSource, btnTxt, ...props}) => {
|
|
const output_name = `${label}`;
|
|
const [columnsMap, setColumnsMap] = useState([]);
|
|
const [summaryRow, setSummaryRow] = useState({});
|
|
useEffect(() => {
|
|
const r1 = columns.reduce((r, v) => ({
|
|
...r,
|
|
...(v.children ? v.children.reduce((rc, vc, ci) => ({
|
|
...rc,
|
|
...(vc?.titleX ? {[`${v?.titleX || v.title},${vc.titleX}`]: vc.titleX } : {[(v?.titleX || v.title) + (vc.key || ci || '')]: `${vc?.titleX || vc?.title || ''}`}),
|
|
}), {}) : {})
|
|
}), {});
|
|
const flatCols = columns.flatMap((v, k) =>
|
|
v.children ? v.children.map((vc, ci) => ({ ...vc, title: `${v?.titleX || v.title}` + (vc?.titleX ? `,${vc.titleX}` : (vc.key || ci || '')) })) : {...v, title: `${v?.titleX || v.title}`}
|
|
);
|
|
// .filter((c) => c.dataIndex)
|
|
// !['string', 'number'].includes(typeof vc.title) ? `${v?.titleX || v.title}` : `${v?.titleX || v.title}-${vc.title || ''}`
|
|
;
|
|
setColumnsMap(flatCols);
|
|
// console.log('flatCols', flatCols);
|
|
|
|
setSummaryRow(r1);
|
|
// console.log('summaryRow', r1);
|
|
|
|
return () => {};
|
|
}, [columns]);
|
|
|
|
const onExport = () => {
|
|
if (isEmpty(dataSource)) {
|
|
message.warning('无结果.');
|
|
return false;
|
|
}
|
|
const data = dataSource.map((item) => {
|
|
const itemMapped = columnsMap.reduce((sv, kset) => {
|
|
const export_val = typeof kset?.dataExport === 'function' ? kset.dataExport('', item) : null;
|
|
const render_val = typeof kset?.render === 'function' ? kset.render('', item) : null;
|
|
const data_val = kset?.dataIndex ? (Array.isArray(kset.dataIndex) ? getNestedValue(item, kset.dataIndex) : item[kset.dataIndex]) : undefined;
|
|
const data_val_str = data_val ? String(data_val) : '';
|
|
const x_val = item[`${kset.dataIndex}_X`];
|
|
// const _title = kset.title.replace('-[object Object]', '');
|
|
const v = { [kset.title]: x_val || export_val || data_val_str || render_val };
|
|
return { ...sv, ...v };
|
|
}, {});
|
|
return itemMapped;
|
|
});
|
|
const ws = utils.json_to_sheet([].concat(isEmpty(summaryRow) ? [] : [summaryRow], data), { header: columnsMap.filter((r) => r.dataIndex).map((r) => r.title) });
|
|
const wb = utils.book_new();
|
|
utils.book_append_sheet(wb, ws, 'sheet');
|
|
writeFile(wb, `${output_name}.xlsx`);
|
|
};
|
|
|
|
return (
|
|
<Button {...props}
|
|
type="link"
|
|
icon={<DownloadOutlined />}
|
|
size="small"
|
|
disabled={false}
|
|
onClick={onExport}
|
|
>
|
|
{btnTxt || '导出excel'}
|
|
</Button>
|
|
);
|
|
};
|