perf: 预设; 导出

feature/pivot
Lei OT 2 years ago
parent 42f4cbd134
commit 8228e07209

@ -177,7 +177,7 @@ export const KPISubjects = [
* @returns
*/
export const pivotBy = (data, [rows, columns, date]) => {
// console.time('pivot----');
console.time('pivot----');
console.log('pivotBy', [rows, columns, date]);
const groupbyKeys = flush([].concat(rows, columns, [date]));
const getKeys = (keys) => keys.map((keyField) => [...new Set(data.map((f) => f[keyField]))]);
@ -278,7 +278,7 @@ export const pivotBy = (data, [rows, columns, date]) => {
const columnsData = groupBy(data, (row) => columns.map((kk) => `${row[kk]}`).join('=@='));
const summaryColumns = transposeData(columns, columnsData, ['rows', rows]);
// console.timeEnd('pivot----');
console.timeEnd('pivot----');
return { data: pivotResult, columnValues: [rowsKeys, columnsKeys, dateKeys], summaryRows, summaryColumns };
};

@ -533,3 +533,17 @@ export const getNestedValue = (obj, keyArr) => {
return acc && acc[curr];
}, obj);
};
/**
* 计算笛卡尔积
*/
export const cartesianProductArray = (arr, sep = '_', index = 0, prefix = '') => {
let result = [];
if(index === arr.length){
return [prefix];
}
arr[index].forEach(item => {
result = result.concat(cartesianProductArray(arr, sep, index+1, prefix ? `${prefix}${sep}${item}` : `${item}`));
});
return result;
};

@ -2,45 +2,37 @@ import { useContext, useEffect, useState } from 'react';
import { observer } from 'mobx-react';
import { useParams } from 'react-router-dom';
import { stores_Context } from '../config';
import { Row, Col, Spin, Table, Select, Typography, Card, Button } from 'antd';
import { cloneDeep, groupBy, isEmpty, omit, pick, sortBy, unique } from '../utils/commons';
import { Row, Col, Spin, Table, Select, Typography, Card, Button, Space, Divider } from 'antd';
import { cloneDeep, groupBy, isEmpty, omit, pick, sortBy, unique, cartesianProductArray } from '../utils/commons';
import { dataFieldAlias, pivotBy } from '../libs/ht';
import SearchForm from '../components/search/SearchForm';
import { Line } from '@ant-design/plots';
import DateGroupRadio from '../components/DateGroupRadio';
import { TableExportBtn } from './../components/Data';
const { Text } = Typography;
const filterFields = [
{ key: 'country', label: '国籍' },
{ key: 'SourceType', label: '来源类型' },
{ key: 'productType', label: '产品类型' },
{ key: 'country', label: '国籍' },
{ key: 'CLI_NO', label: '线路' },
// { key: 'destination', label: '' },
{ key: 'COLI_LineClass', label: '页面类型' },
{ key: 'guestGroupType', label: '客群类别' },
{ key: 'travelMotivation', label: '出行动机' },
{ key: 'operatorName', label: '顾问' },
{ key: 'WebCode', label: '来源站点' },
// todo: , , [PPC, NL...]
// { key: 'operatorName', label: '' },
// { key: 'WebCode', label: '' },
// todo: , , LineClass[PPC, NL...], 线line,
];
const filterFieldsMapped = filterFields.reduce((r, v) => ({ ...r, [v.key]: v }), {});
const quickOptions = [
{ label: '国籍×产品', fields: [['country'], ['productType']] },
{ label: '产品×客群', fields: [['productType'], ['guestGroupType']] },
// { label: '×', fields: [['country'], ['productType']] },
{ label: '[ 产品×客群 ]×[ ]', fields: [['productType', 'guestGroupType'], []] },
{ label: '[ 国籍×客群 ]×[ ]', fields: [['country', 'guestGroupType'], []] },
// { label: '[ × ]×[ ]', fields: [['country', 'guestGroupType'], []] },
];
/**
* 计算笛卡尔积
*/
const cartesianProductArray = (arr, sep = '_', index = 0, prefix = '') => {
let result = [];
if(index === arr.length){
return [prefix];
}
arr[index].forEach(item => {
result = result.concat(cartesianProductArray(arr, sep, index+1, prefix ? `${prefix}${sep}${item}` : `${item}`));
});
return result;
};
// TdCellDataTable
const TdCell = (tdprops) => {
// onMouseEnter, onMouseLeave
@ -151,21 +143,36 @@ export default observer((props) => {
//
// const [leftFields, setLeftFields] = useState(filterFields);
const [rightFields, setRightFields] = useState(filterFields);
const [rightFields, setRightFields] = useState(filterFields); // select option
const [rowFields, setRowFields] = useState([]);
const [columnFields, setColumnFields] = useState([]);
//
const [rowSelection, setRowSelection] = useState();
const [columnSelection, setColumnSelection] = useState();
const quickOpt = (i) => {
const { fields: pivotFields } = quickOptions[i];
const [row, col] = pivotFields;
setRowSelection(Object.values(pick(filterFieldsMapped, row)));
setColumnSelection(filterFieldsMapped[col[0]]);
!isEmpty(col) ? setColumnSelection(filterFieldsMapped[col[0]]) : setColumnSelection([]);
setRowFields(row);
resetItemFilter();
setPivotDateColumns(pivotFields);
};
const resetFields = () => {
// setRowFields([]);
// setColumnFields([]);
setRowSelection([]);
setColumnSelection([]);
resetItemFilter();
setPivotDateColumns([[], []]);
};
const handleRowsPick = (v) => {
setRowSelection(v);
const pickKeys = v.map((ele) => ele.key);
setRowFields(pickKeys);
// const leftFieldsMapped = leftFields.reduce((r, v) => ({ ...r, [v.key]: v }), {});
@ -177,6 +184,7 @@ export default observer((props) => {
};
const handleColsPick = (val) => {
setColumnSelection(val);
const pickKeys = isEmpty(val) ? [] : Array.isArray(val) ? val.map((ele) => ele.key) : [val.key];
setColumnFields(pickKeys);
const afterLeft = Object.values(omit(filterFieldsMapped, rowFields));
@ -323,11 +331,19 @@ export default observer((props) => {
<Card
size={'small'}
title={'透视选项'}
// extra={quickOptions.map((ele, elei) => (
// <Button key={ele.label} type="link" onClick={() => quickOpt(elei)}>
// {ele.label}
// </Button>
// ))}
extra={
<Space>
<Text type={'secondary'}>预设:</Text>
{quickOptions.map((ele, elei) => (
<Button key={ele.label} onClick={() => quickOpt(elei)} type={'primary'} ghost size={'small'}>
{ele.label}
</Button>
))}
<Button key={'reset-quick'} onClick={resetFields} type={'primary'} ghost size={'small'}>
重置
</Button>
</Space>
}
>
<Row gutter={16}>
<Col span={24}>
@ -352,8 +368,7 @@ export default observer((props) => {
style={{ width: '100%' }}
placeholder={`选择`}
onChange={(v) => handleRowsPick(v)}
// value={sale_store.salesTrade.pickSales}
// value={rowSelection}
value={rowSelection}
maxTagCount={2}
maxTagPlaceholder={(omittedValues) => ` + ${omittedValues.length} 更多...`}
allowClear={true}
@ -413,8 +428,7 @@ export default observer((props) => {
style={{ width: '100%' }}
placeholder={`选择`}
onChange={(v) => handleColsPick(v)}
// value={sale_store.salesTrade.pickSales}
// value={columnSelection}
value={columnSelection}
maxTagCount={2}
maxTagPlaceholder={(omittedValues) => ` + ${omittedValues.length} 更多...`}
allowClear={true}
@ -494,6 +508,9 @@ export default observer((props) => {
<h3>
透视汇总表: <span style={{ fontSize: 'smaller' }}>{dataFieldAlias[lineConfig.yField].label}</span>
</h3>
<Divider orientation="right">
<TableExportBtn label={'pivot'} {...{ columns: targetTableProps.columns, dataSource: pivotTableDataSource }} />
</Divider>
<Table {...targetTableProps} dataSource={pivotTableDataSource} components={{ body: { cell: TdCell } }} />
</Spin>
</section>

Loading…
Cancel
Save