Merge branch 'feature/pivot'

# Conflicts:
#	src/components/Data.jsx
#	src/views/DataPivot.jsx
feature/year-over-year
Lei OT 2 years ago
commit bfc953a211

@ -84,6 +84,7 @@ const App = () => {
{ key: 51, label: <NavLink to="/sale">业绩数据</NavLink> }, { key: 51, label: <NavLink to="/sale">业绩数据</NavLink> },
{ key: 52, label: <NavLink to="/sale_kpi">销售进度</NavLink> }, { key: 52, label: <NavLink to="/sale_kpi">销售进度</NavLink> },
{ key: 'distribution', label: <NavLink to="/distribution">统计分布</NavLink> }, { key: 'distribution', label: <NavLink to="/distribution">统计分布</NavLink> },
{ key: 'trade-pivot', label: <NavLink to="/trade/pivot">数据透视</NavLink> },
], ],
}, },
{ {
@ -218,6 +219,7 @@ const App = () => {
<Route path="/sale_sub/:type_sub" element={<Sale_sub />} /> <Route path="/sale_sub/:type_sub" element={<Sale_sub />} />
<Route path="/sale_kpi" element={<Sale_KPI />} /> <Route path="/sale_kpi" element={<Sale_KPI />} />
<Route path="/distribution" element={<Distribution />} /> <Route path="/distribution" element={<Distribution />} />
<Route path="/:page/pivot" element={<DataPivot />} />
</Route> </Route>
</Routes> </Routes>
</Content> </Content>

@ -1,5 +1,5 @@
import moment from 'moment'; import moment from 'moment';
import { groupBy } from '../../utils/commons'; import { fixTo2Decimals, groupBy } from '../../utils/commons';
export const datePartOptions = [ export const datePartOptions = [
{ label: '日', value: 'day' }, { label: '日', value: 'day' },
@ -83,7 +83,7 @@ export const parseDateType = (data, dateType = 'day', { dateKey, valueKey, serie
const dateRange = [min, max]; const dateRange = [min, max];
const summaryVal = everySeries[key].reduce((rows, row) => rows + row[valueKey], 0); const summaryVal = everySeries[key].reduce((rows, row) => rows + row[valueKey], 0);
const retValue = _f === 'sum' ? summaryVal : _calcF(summaryVal, everySeries[key].length); const retValue = _f === 'sum' ? summaryVal : _calcF(summaryVal, everySeries[key].length);
a.push({ groupKey: key, value: retValue, dateKey: dateRangeStr, dateRange, containDate, [seriesKey]: _seriesKey, [dateKey]: _dateKey }); a.push({ groupKey: key, value: fixTo2Decimals(retValue), dateKey: dateRangeStr, dateRange, containDate, [seriesKey]: _seriesKey, [dateKey]: _dateKey });
return a; return a;
}, []); }, []);
const avgDiv = [...new Set(dateArr)].length; const avgDiv = [...new Set(dateArr)].length;
@ -108,7 +108,7 @@ export const resultDataCb = (dataRaw, dateGroup, { data1, data2 }, fieldMapper,
const _data2 = data2 ? dataRaw[data2] : []; const _data2 = data2 ? dataRaw[data2] : [];
const parse1 = parseDateType(_data1, dateGroup, fieldMapper); const parse1 = parseDateType(_data1, dateGroup, fieldMapper);
const parseData1 = parse1.data.map((ele) => ({ const parseData1 = parse1.data.map((ele) => ({
[fieldMapper.dateKey]: ele[fieldMapper.dateKey], [fieldMapper.dateKey]: ele[fieldMapper.dateKey] === 'Invalid date' ? '空日期' : ele[fieldMapper.dateKey],
[fieldMapper.valueKey]: ele.value, [fieldMapper.valueKey]: ele.value,
[fieldMapper.seriesKey]: ele[fieldMapper.seriesKey], [fieldMapper.seriesKey]: ele[fieldMapper.seriesKey],
groups: _data1[0].groups, groups: _data1[0].groups,
@ -118,7 +118,7 @@ export const resultDataCb = (dataRaw, dateGroup, { data1, data2 }, fieldMapper,
})); }));
const parse2 = parseDateType(_data2, dateGroup, fieldMapper); const parse2 = parseDateType(_data2, dateGroup, fieldMapper);
const parseData2 = parse2.data.map((ele) => ({ const parseData2 = parse2.data.map((ele) => ({
[fieldMapper.dateKey]: ele[fieldMapper.dateKey], [fieldMapper.dateKey]: ele[fieldMapper.dateKey] === 'Invalid date' ? '空日期' : ele[fieldMapper.dateKey],
// [fieldMapper.dateKey]: ele.groupKey, // [fieldMapper.dateKey]: ele.groupKey,
[fieldMapper.valueKey]: ele.value, [fieldMapper.valueKey]: ele.value,
[fieldMapper.seriesKey]: ele[fieldMapper.seriesKey], [fieldMapper.seriesKey]: ele[fieldMapper.seriesKey],
@ -151,8 +151,15 @@ export const resultDataCb = (dataRaw, dateGroup, { data1, data2 }, fieldMapper,
[fieldMapper.dateKey]: keyMapped[ele[fieldMapper.dateKey]], [fieldMapper.dateKey]: keyMapped[ele[fieldMapper.dateKey]],
dateKey: ele.dateKey, dateKey: ele.dateKey,
})); }));
const retData = [].concat(parseData1, reindexData2 ).map(ele => ({...ele, [fieldMapper.dateKey]: data1KeyMappedStr[ele[fieldMapper.dateKey]] || data2KeyMappedStr[ele[fieldMapper.dateKey]]})); const retData = [].concat(parseData1, reindexData2 ).map(ele => ({...ele,
[fieldMapper.dateKey]: data1KeyMappedStr[ele[fieldMapper.dateKey]] === 'Invalid date' ? '空日期' : (data1KeyMappedStr[ele[fieldMapper.dateKey]] || data2KeyMappedStr[ele[fieldMapper.dateKey]])}));
const avg1 = parse1.avgVal; const avg1 = parse1.avgVal;
// console.log('callback', dateGroup, retData, avg1, parse2.avgVal, data1KeyMappedStr, data2KeyMappedStr); // console.log('callback','\ndateGroup', dateGroup,
// '\nretData', retData,
// '\navg1', avg1,
// '\nparse2', parse2.avgVal,
// '\ndata1KeyMappedStr', data1KeyMappedStr,
// '\ndata2KeyMappedStr', data2KeyMappedStr
// );
cb(dateGroup, retData, avg1, parse2.avgVal); cb(dateGroup, retData, avg1, parse2.avgVal);
}; };

@ -1,4 +1,4 @@
import { fixTo4Decimals, fixTo1Decimals, fixToInt, groupBy, sortBy, cloneDeep, pick, unique, flush } from '../utils/commons'; import { fixTo4Decimals, fixTo1Decimals, fixToInt, groupBy, sortBy, cloneDeep, pick, unique, flush, fixTo2Decimals } from '../utils/commons';
/** /**
* 事业部 * 事业部
@ -91,7 +91,7 @@ export const sites = [
export const sitesMappedByCode = sites.reduce((a, c) => ({ ...a, [String(c.code)]: { ...c, key: c.code, value: c.code } }), {}); export const sitesMappedByCode = sites.reduce((a, c) => ({ ...a, [String(c.code)]: { ...c, key: c.code, value: c.code } }), {});
export const dateTypes = [ export const dateTypes = [
{ key: 'applyDate', value: 'applyDate', label: '提交日期' }, { key: 'applyDate', value: 'applyDate', label: '提交日期' },
{ key: 'ConfirmDate', value: 'ConfirmDate', label: '确认日期' }, { key: 'confirmDate', value: 'confirmDate', label: '确认日期' },
{ key: 'startDate', value: 'startDate', label: '走团日期' }, { key: 'startDate', value: 'startDate', label: '走团日期' },
]; ];
@ -177,11 +177,12 @@ export const KPISubjects = [
* @returns * @returns
*/ */
export const pivotBy = (data, [rows, columns, date]) => { export const pivotBy = (data, [rows, columns, date]) => {
// console.time('pivot----'); console.time('pivot3----');
console.log('pivotBy', [rows, columns, date]); console.log('pivotBy', [rows, columns, date]);
const groupbyKeys = flush([].concat(rows, columns, [date])); const groupbyKeys = flush([].concat(rows, columns, [date]));
const getKeys = (keys) => keys.map((keyField) => [...new Set(data.map((f) => f[keyField]))]); const getKeys = (keys) => keys.map((keyField) => [...new Set(data.map((f) => f[keyField]))]);
const [rowsKeys, columnsKeys, dateKeys] = [getKeys(rows), getKeys(columns), getKeys([date])]; const [rowsKeys, columnsKeys, dateKeys] = [getKeys(rows), getKeys(columns), [getKeys([date])[0].filter(s => s)]];
// console.log('rowsKeys', rowsKeys, 'columnsKeys', columnsKeys, 'dateKeys', dateKeys);
const calcTradeFields = (dataObj, keepKeys = [], seriesKey = '') => { const calcTradeFields = (dataObj, keepKeys = [], seriesKey = '') => {
const outerKeys = []; const outerKeys = [];
@ -209,9 +210,11 @@ export const pivotBy = (data, [rows, columns, date]) => {
SumOrder: _len, SumOrder: _len,
SumPersonNum: 0, SumPersonNum: 0,
ConfirmPersonNum: 0,
ConfirmOrder: 0, ConfirmOrder: 0,
transactions: 0, transactions: 0,
SumML: 0, SumML: 0,
SumML_txt: '',
quotePrice: 0, quotePrice: 0,
tourdays: 0, tourdays: 0,
applyDays: 0, applyDays: 0,
@ -220,9 +223,10 @@ export const pivotBy = (data, [rows, columns, date]) => {
const calculatedData = dataObj[colKey].reduce((r, v) => { const calculatedData = dataObj[colKey].reduce((r, v) => {
r.SumPersonNum += v.personNum; r.SumPersonNum += v.personNum;
r.ConfirmPersonNum += Number(v.orderState) === 1 ? v.personNum : 0;
r.ConfirmOrder += Number(v.orderState) === 1 ? 1 : 0; r.ConfirmOrder += Number(v.orderState) === 1 ? 1 : 0;
r.transactions += v.transactions; r.transactions += v.transactions;
r.SumML += v.ML; r.SumML += Number(v.orderState) === 1 ? v.ML : 0;
r.quotePrice += v.quotePrice; r.quotePrice += v.quotePrice;
r.tourdays += v.tourdays; r.tourdays += v.tourdays;
r.applyDays += v.applyDays; r.applyDays += v.applyDays;
@ -238,6 +242,13 @@ export const pivotBy = (data, [rows, columns, date]) => {
ConfirmRates: calculatedData.ConfirmOrder ? fixTo4Decimals(calculatedData.ConfirmOrder / calculatedData.SumOrder) : 0, ConfirmRates: calculatedData.ConfirmOrder ? fixTo4Decimals(calculatedData.ConfirmOrder / calculatedData.SumOrder) : 0,
OrderValue: calculatedData.SumOrder ? fixToInt(calculatedData.SumML / calculatedData.SumOrder) : 0, OrderValue: calculatedData.SumOrder ? fixToInt(calculatedData.SumML / calculatedData.SumOrder) : 0,
}; };
// Formatter
calculatedData.transactions = fixTo2Decimals(calculatedData.transactions);
calculatedData.SumML = fixTo2Decimals(calculatedData.SumML);
calculatedData.SumML_txt = dataFieldAlias.SumML.formatter(calculatedData.SumML);
calculatedData.quotePrice = fixTo2Decimals(calculatedData.quotePrice);
calculatedData.ConfirmRates_txt = dataFieldAlias.ConfirmRates.formatter(_rowCalc.ConfirmRates);
DataGroupByKeys[colKey] = { ...calculatedData, ..._rowCalc }; DataGroupByKeys[colKey] = { ...calculatedData, ..._rowCalc };
}); });
@ -259,16 +270,19 @@ export const pivotBy = (data, [rows, columns, date]) => {
.map((everyR) => { .map((everyR) => {
const _colKey = dataKey || 'dataKey'; const _colKey = dataKey || 'dataKey';
const allColumns = Object.values(everyR[_colKey]).reduce((r, c) => r.concat([c]), []); const allColumns = Object.values(everyR[_colKey]).reduce((r, c) => r.concat([c]), []);
const summaryCalc = ['ConfirmOrder', 'SumOrder', 'SumML', 'transactions', 'SumPersonNum', 'quotePrice', 'tourdays', 'applyDays', 'confirmDays'].reduce( const summaryCalc = ['ConfirmOrder', 'SumOrder', 'SumML', 'transactions', 'SumPersonNum', 'ConfirmPersonNum', 'quotePrice', 'tourdays', 'applyDays', 'confirmDays'].reduce(
(r, skey) => ({ ...r, [skey]: allColumns.reduce((a, c) => a + c[skey], 0) }), (r, skey) => ({ ...r, [skey]: allColumns.reduce((a, c) => Number(c.orderState) === 1 ? a : fixTo2Decimals(a + c[skey]), 0) }),
everyR everyR
); );
summaryCalc.tourdays = Math.ceil(summaryCalc.tourdays / allColumns.length); summaryCalc.tourdays = Math.ceil(summaryCalc.tourdays / allColumns.length);
summaryCalc.applyDays = Math.ceil(summaryCalc.applyDays / allColumns.length); summaryCalc.applyDays = Math.ceil(summaryCalc.applyDays / allColumns.length);
summaryCalc.confirmDays = Math.ceil(summaryCalc.confirmDays / allColumns.length); summaryCalc.confirmDays = Math.ceil(summaryCalc.confirmDays / allColumns.length);
summaryCalc.ConfirmRates = summaryCalc.ConfirmOrder ? fixTo4Decimals(summaryCalc.ConfirmOrder / summaryCalc.SumOrder) : 0; summaryCalc.ConfirmRates = summaryCalc.ConfirmOrder ? fixTo2Decimals(summaryCalc.ConfirmOrder / summaryCalc.SumOrder*100) : 0;
summaryCalc.OrderValue = summaryCalc.SumOrder ? fixToInt(summaryCalc.SumML / summaryCalc.SumOrder) : 0; summaryCalc.OrderValue = summaryCalc.SumOrder ? fixToInt(summaryCalc.SumML / summaryCalc.SumOrder) : 0;
summaryCalc.SumML_txt = dataFieldAlias.SumML.formatter(summaryCalc.SumML);
summaryCalc.ConfirmRates_txt = dataFieldAlias.ConfirmRates.formatter(summaryCalc.ConfirmRates);
return { ...everyR, ...summaryCalc }; return { ...everyR, ...summaryCalc };
}); });
@ -278,7 +292,7 @@ export const pivotBy = (data, [rows, columns, date]) => {
const columnsData = groupBy(data, (row) => columns.map((kk) => `${row[kk]}`).join('=@=')); const columnsData = groupBy(data, (row) => columns.map((kk) => `${row[kk]}`).join('=@='));
const summaryColumns = transposeData(columns, columnsData, ['rows', rows]); const summaryColumns = transposeData(columns, columnsData, ['rows', rows]);
// console.timeEnd('pivot----'); console.timeEnd('pivot3----');
return { data: pivotResult, columnValues: [rowsKeys, columnsKeys, dateKeys], summaryRows, summaryColumns }; return { data: pivotResult, columnValues: [rowsKeys, columnsKeys, dateKeys], summaryRows, summaryColumns };
}; };

@ -37,12 +37,14 @@ class Trade {
resetData = () => { resetData = () => {
this.detailData = { this.detailData = {
orders: { loading: false, dataSource: [], originData: [] }, orders: { loading: false, dataSource: [], originData: [] },
trade: { loading: false, dataSource: [], originData: [] },
}; };
}; };
searchValues = {}; searchValues = {};
detailData = { detailData = {
orders: { loading: false, dataSource: [], originData: [] }, orders: { loading: false, dataSource: [], originData: [] },
trade: { loading: false, dataSource: [], originData: [] },
}; };
} }

@ -45,7 +45,7 @@ class DatePickerStore {
'DepartmentList': { 'key': 'ALL', 'label': '所有小组' }, 'DepartmentList': { 'key': 'ALL', 'label': '所有小组' },
'WebCode': { 'key': 'ALL', 'label': '所有来源' }, 'WebCode': { 'key': 'ALL', 'label': '所有来源' },
'IncludeTickets': { 'key': '1', 'label': '含门票' }, 'IncludeTickets': { 'key': '1', 'label': '含门票' },
'DateType': { 'key': 'ConfirmDate', 'label': '确认日期' }, 'DateType': { 'key': 'confirmDate', 'label': '确认日期' },
'year': this.start_date, 'year': this.start_date,
// 'months': [moment(), moment()], // 'months': [moment(), moment()],
'dates': [this.start_date, this.end_date], 'dates': [this.start_date, this.end_date],
@ -55,7 +55,7 @@ class DatePickerStore {
DepartmentList: 'ALL', DepartmentList: 'ALL',
WebCode: 'ALL', WebCode: 'ALL',
IncludeTickets: '1', IncludeTickets: '1',
DateType: 'ConfirmDate', DateType: 'confirmDate',
Date1: this.start_date.format('YYYY-MM-DD'), Date1: this.start_date.format('YYYY-MM-DD'),
Date2: this.end_date.format('YYYY-MM-DD 23:59:59'), Date2: this.end_date.format('YYYY-MM-DD 23:59:59'),
}; };

@ -33,7 +33,7 @@ class SaleStore {
date_title = 'date_title'; // 日期段,只用于显示,防止日期选择控件的变化导致页面刷新 date_title = 'date_title'; // 日期段,只用于显示,防止日期选择控件的变化导致页面刷新
searchValues = { searchValues = {
DateType: { key: 'ConfirmDate', label: '确认日期'}, DateType: { key: 'confirmDate', label: '确认日期'},
WebCode: { key: 'All', label: '所有来源'}, WebCode: { key: 'All', label: '所有来源'},
IncludeTickets: { key: '1', label: '含门票'}, IncludeTickets: { key: '1', label: '含门票'},
DepartmentList: [groupsMappedByCode.GH], DepartmentList: [groupsMappedByCode.GH],

@ -533,3 +533,17 @@ export const getNestedValue = (obj, keyArr) => {
return acc && acc[curr]; return acc && acc[curr];
}, obj); }, 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,12 +2,13 @@ import { useContext, useEffect, useState } from 'react';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { stores_Context } from '../config'; import { stores_Context } from '../config';
import { Row, Col, Spin, Table, Select, Typography, Card, Button } from 'antd'; import { Row, Col, Spin, Table, Select, Typography, Card, Button, Space, Divider } from 'antd';
import { cloneDeep, groupBy, isEmpty, omit, pick, sortBy, unique } from '../utils/commons'; import { cloneDeep, groupBy, isEmpty, omit, pick, sortBy, unique, cartesianProductArray } from '../utils/commons';
import { dataFieldAlias, pivotBy } from '../libs/ht'; import { dataFieldAlias, pivotBy } from '../libs/ht';
import SearchForm from '../components/search/SearchForm'; import SearchForm from '../components/search/SearchForm';
import { Line } from '@ant-design/plots'; import { Line } from '@ant-design/plots';
import DateGroupRadio from '../components/DateGroupRadio'; import DateGroupRadio from '../components/DateGroupRadio';
import { TableExportBtn } from './../components/Data';
const { Text } = Typography; const { Text } = Typography;
@ -22,28 +23,18 @@ const filterFields = [
{ key: 'travelMotivation', label: '出行目的' }, { key: 'travelMotivation', label: '出行目的' },
// { key: 'operatorName', label: '' }, // { key: 'operatorName', label: '' },
// { key: 'WebCode', label: '' }, // { key: 'WebCode', label: '' },
// todo: , , LineClass[PPC, NL...], 线line, // todo: , ,
]; ];
const filterFieldsMapped = filterFields.reduce((r, v) => ({ ...r, [v.key]: v }), {}); const filterFieldsMapped = filterFields.reduce((r, v) => ({ ...r, [v.key]: v }), {});
/** 预设的选项, 只有行 */
const quickOptions = [ const quickOptions = [
{ label: '国籍×产品', fields: [['country'], ['productType']] }, // { label: '×', fields: [['country'], ['productType']] },
{ label: '产品×客群', fields: [['productType'], ['guestGroupType']] }, { 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 // TdCellDataTable
const TdCell = (tdprops) => { const TdCell = (tdprops) => {
// onMouseEnter, onMouseLeave // onMouseEnter, onMouseLeave
@ -51,12 +42,37 @@ const TdCell = (tdprops) => {
return <td {...restProps} />; return <td {...restProps} />;
}; };
const pageSetting = {
orders: {
xField: 'applyDate',
yField: 'SumOrder',
tableColumns: [
{ key: 'SumOrder', title: '订单数', dataIndex: 'SumOrder', width: '5em' },
// { key: 'ConfirmOrder', title: '', dataIndex: 'ConfirmOrder', width: '5em' },
// { key: 'ConfirmPersonNum', title: '', dataIndex: 'ConfirmPersonNum', width: '5em' },
// { key: 'ConfirmRates', title: '', dataIndex: 'ConfirmRates_txt', width: '5em' },
// { key: 'SumML', title: '', dataIndex: 'SumML_txt', width: '5em' },
],
searchInitial: { DateType: { key: 'applyDate', value: 'applyDate', label: '提交日期' } },
},
trade: {
xField: 'confirmDate',
yField: 'SumML',
yFieldAlias: 'SumML_txt',
tableColumns: [{ key: 'SumML', title: '毛利', dataIndex: 'SumML', width: '5em' }], // SumML_txt
searchInitial: { DateType: { key: 'confirmDate', value: 'confirmDate', label: '确认日期' } },
},
};
export default observer((props) => { export default observer((props) => {
const { page } = useParams(); const { page } = useParams();
const { date_picker_store: searchFormStore, orders_store, DistributionStore, DataPivotStore } = useContext(stores_Context); const { date_picker_store: searchFormStore, orders_store, DataPivotStore } = useContext(stores_Context);
const { formValues, formValuesToSub } = searchFormStore; const { formValues, formValuesToSub } = searchFormStore;
const { originData } = DataPivotStore.detailData[page]; const { originData } = DataPivotStore.detailData[page];
const { xField: defaultDateType, yField: defaultValKey, yFieldAlias, tableColumns, searchInitial } = pageSetting[page];
const [curXfield, setCurXfield] = useState(defaultDateType);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [rawData, setRawData] = useState(originData || []); const [rawData, setRawData] = useState(originData || []);
const [dataBeforePick, setDataBeforePick] = useState([]); const [dataBeforePick, setDataBeforePick] = useState([]);
@ -86,6 +102,14 @@ export default observer((props) => {
return () => {}; return () => {};
}, [dataSource]); }, [dataSource]);
useEffect(() => {
setCurXfield(formValuesToSub.DateType);
setLineConfig({...lineConfig, xField: formValuesToSub.DateType});
return () => {};
}, [formValues]);
const detailRefresh = async (obj) => { const detailRefresh = async (obj) => {
setLoading(true); setLoading(true);
DataPivotStore.getDetailData({ DataPivotStore.getDetailData({
@ -99,24 +123,22 @@ export default observer((props) => {
}); });
}; };
const valKey = 'SumOrder';
const timesKey = 'applyDate';
/** /**
* 走势的数据 * 走势的数据
* 汇总 * 汇总
*/ */
const calcDataByDate = (_rawData) => { const calcDataByDate = (_rawData) => {
// console.log(';;;;;', pivotDateColumns); // console.log(';;;;;', pivotDateColumns);
const { data, columnValues, summaryRows, summaryColumns } = pivotBy(_rawData || rawData, [].concat(pivotDateColumns, [timesKey])); const { data, columnValues, summaryRows, summaryColumns } = pivotBy(_rawData || rawData, [].concat(pivotDateColumns, [curXfield]));
// console.log('data====', data, '\ncolumnValues', columnValues, '\nsummaryRows', summaryRows, '\nsummaryColumns', summaryColumns); // console.log('data====', data, '\ncolumnValues', columnValues, '\nsummaryRows', summaryRows, '\nsummaryColumns', summaryColumns);
setDataBeforePick(data.sort(sortBy(timesKey))); setDataBeforePick(data.sort(sortBy(curXfield)));
// 线 // 线
setDataSource(data.sort(sortBy(timesKey))); setDataSource(data.sort(sortBy(curXfield)));
// //
const sortRowData = cloneDeep(summaryRows).sort(sortBy(valKey)).reverse(); const sortRowData = cloneDeep(summaryRows).sort(sortBy(defaultValKey)).reverse();
setPivotTableDataSource(sortRowData); setPivotTableDataSource(sortRowData);
// //
const sortColData = summaryColumns.sort(sortBy(valKey)).reverse(); const sortColData = summaryColumns.sort(sortBy(defaultValKey)).reverse();
const colDataMapped = isEmpty(pivotDateColumns[1]) ? sortColData[0] : sortColData.reduce((r, v) => ({...r, [v[pivotDateColumns[1][0]]]: v}), {}); const colDataMapped = isEmpty(pivotDateColumns[1]) ? sortColData[0] : sortColData.reduce((r, v) => ({...r, [v[pivotDateColumns[1][0]]]: v}), {});
setPivotTableColumnSummary(colDataMapped); setPivotTableColumnSummary(colDataMapped);
// //
@ -129,8 +151,8 @@ export default observer((props) => {
const line_config = { const line_config = {
// data: dataSource, // data: dataSource,
padding: 'auto', padding: 'auto',
xField: timesKey, xField: curXfield,
yField: valKey, yField: defaultValKey,
seriesField: 'rowLabel', seriesField: 'rowLabel',
// xAxis: { // xAxis: {
// type: 'timeCat', // type: 'timeCat',
@ -139,6 +161,9 @@ export default observer((props) => {
min: 0, min: 0,
maxTickInterval: 5, maxTickInterval: 5,
}, },
meta: {
...cloneDeep(dataFieldAlias),
},
// smooth: true, // smooth: true,
label: {}, // label: {}, //
legend: { legend: {
@ -149,7 +174,6 @@ export default observer((props) => {
itemMarginBottom: 12, // itemMarginBottom: 12, //
}, },
}; };
const [lineConfig, setLineConfig] = useState(cloneDeep(line_config)); const [lineConfig, setLineConfig] = useState(cloneDeep(line_config));
// //
@ -157,18 +181,33 @@ export default observer((props) => {
const [rightFields, setRightFields] = useState(filterFields); const [rightFields, setRightFields] = useState(filterFields);
const [rowFields, setRowFields] = useState([]); const [rowFields, setRowFields] = useState([]);
const [columnFields, setColumnFields] = useState([]); const [columnFields, setColumnFields] = useState([]);
const [rowSelection, setRowSelection] = useState(); const [rowSelection, setRowSelection] = useState();
const [columnSelection, setColumnSelection] = useState(); const [columnSelection, setColumnSelection] = useState();
//
const quickOpt = (i) => { const quickOpt = (i) => {
const { fields: pivotFields } = quickOptions[i]; const { fields: pivotFields } = quickOptions[i];
const [row, col] = pivotFields; const [row, col] = pivotFields;
setRowSelection(Object.values(pick(filterFieldsMapped, row))); setRowSelection(Object.values(pick(filterFieldsMapped, row)));
setColumnSelection(filterFieldsMapped[col[0]]); !isEmpty(col) ? setColumnSelection(filterFieldsMapped[col[0]]) : setColumnSelection([]);
setRowFields(row);
setColumnFields(col);
resetItemFilter();
setPivotDateColumns(pivotFields); setPivotDateColumns(pivotFields);
}; };
const resetFields = () => {
setRowFields([]);
setColumnFields([]);
setRowSelection([]);
setColumnSelection([]);
resetItemFilter();
setPivotDateColumns([[], []]);
};
const handleRowsPick = (v) => { const handleRowsPick = (v) => {
setRowSelection(v);
const pickKeys = v.map((ele) => ele.key); const pickKeys = v.map((ele) => ele.key);
setRowFields(pickKeys); setRowFields(pickKeys);
// const leftFieldsMapped = leftFields.reduce((r, v) => ({ ...r, [v.key]: v }), {}); // const leftFieldsMapped = leftFields.reduce((r, v) => ({ ...r, [v.key]: v }), {});
@ -180,6 +219,7 @@ export default observer((props) => {
}; };
const handleColsPick = (val) => { const handleColsPick = (val) => {
setColumnSelection(val);
const pickKeys = isEmpty(val) ? [] : Array.isArray(val) ? val.map((ele) => ele.key) : [val.key]; const pickKeys = isEmpty(val) ? [] : Array.isArray(val) ? val.map((ele) => ele.key) : [val.key];
setColumnFields(pickKeys); setColumnFields(pickKeys);
const afterLeft = Object.values(omit(filterFieldsMapped, rowFields)); const afterLeft = Object.values(omit(filterFieldsMapped, rowFields));
@ -237,7 +277,7 @@ export default observer((props) => {
const dataMapped = groupBy(afterRowsFilter, (row) => row[columnsName]); const dataMapped = groupBy(afterRowsFilter, (row) => row[columnsName]);
const pickData = isEmpty(v) ? afterRowsFilter : Array.isArray(v) ? v.reduce((r, v) => r.concat(dataMapped[v.value]), []) : dataMapped[v.value]; const pickData = isEmpty(v) ? afterRowsFilter : Array.isArray(v) ? v.reduce((r, v) => r.concat(dataMapped[v.value]), []) : dataMapped[v.value];
setDataSource(allFilterValues.length === 0 ? dataBeforePick : pickData.sort(sortBy(timesKey))); setDataSource(allFilterValues.length === 0 ? dataBeforePick : pickData.sort(sortBy(curXfield)));
resetX(); resetX();
}; };
@ -245,7 +285,7 @@ export default observer((props) => {
const [lineChartX, setLineChartX] = useState('day'); const [lineChartX, setLineChartX] = useState('day');
const [avgLine1, setAvgLine1] = useState(0); const [avgLine1, setAvgLine1] = useState(0);
const orderCountDataMapper = { data1: 'data1', data2: undefined }; const orderCountDataMapper = { data1: 'data1', data2: undefined };
const orderCountDataFieldMapper = { 'dateKey': timesKey, 'valueKey': valKey, 'seriesKey': 'rowLabel', _f: 'sum' }; const orderCountDataFieldMapper = { 'dateKey': curXfield, 'valueKey': defaultValKey, 'seriesKey': 'rowLabel', _f: 'sum' };
const resetX = () => { const resetX = () => {
setLineChartX('day'); setLineChartX('day');
setAvgLine1(0); setAvgLine1(0);
@ -283,15 +323,15 @@ export default observer((props) => {
pagination: false, pagination: false,
columns: [ columns: [
...pivotDateColumns[0].map((ele) => ({ key: ele, title: filterFieldsMapped[ele].label, dataIndex: ele, width: '6em', fixed: 'left' })), ...pivotDateColumns[0].map((ele) => ({ key: ele, title: filterFieldsMapped[ele].label, dataIndex: ele, width: '6em', fixed: 'left' })),
{ key: 'SumOrder', title: '订单数', dataIndex: 'SumOrder', width: '5em' }, ...tableColumns,
...pivotDateColumns[1].map((ele) => ({ ...pivotDateColumns[1].map((ele) => ({
key: ele, key: ele,
title: filterFieldsMapped[ele].label, title: filterFieldsMapped[ele].label,
align: 'left', className: 'p-s1', align: 'left', className: 'p-s1',
children: cloneDeep(pivotDateColumnsValues[1][0] || []).map((col) => ({ children: cloneDeep(pivotDateColumnsValues[1][0] || []).map((col) => ({
key: col, key: col,
title: `${col || '(空)'}: ${pivotTableColumnSummary[col]?.[valKey]}`, title: `${col || '(空)'}: ${pivotTableColumnSummary[col]?.[defaultValKey]}`,
dataIndex: ['columns', col, valKey], dataIndex: ['columns', col, defaultValKey || yFieldAlias],
width: '6em', width: '6em',
})), })),
})), })),
@ -307,6 +347,7 @@ export default observer((props) => {
initialValue: { initialValue: {
...formValues, ...formValues,
...orders_store.searchValues, ...orders_store.searchValues,
...searchInitial,
}, },
shows: ['DateType', 'DepartmentList', 'WebCode', 'IncludeTickets', 'dates'], // 'country' shows: ['DateType', 'DepartmentList', 'WebCode', 'IncludeTickets', 'dates'], // 'country'
fieldProps: { fieldProps: {
@ -326,11 +367,19 @@ export default observer((props) => {
<Card <Card
size={'small'} size={'small'}
title={'透视选项'} title={'透视选项'}
// extra={quickOptions.map((ele, elei) => ( extra={
// <Button key={ele.label} type="link" onClick={() => quickOpt(elei)}> <Space>
// {ele.label} <Text type={'secondary'}>预设:</Text>
// </Button> {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}> <Row gutter={16}>
<Col span={24}> <Col span={24}>
@ -355,8 +404,7 @@ export default observer((props) => {
style={{ width: '100%' }} style={{ width: '100%' }}
placeholder={`选择`} placeholder={`选择`}
onChange={(v) => handleRowsPick(v)} onChange={(v) => handleRowsPick(v)}
// value={sale_store.salesTrade.pickSales} value={rowSelection}
// value={rowSelection}
maxTagCount={2} maxTagCount={2}
maxTagPlaceholder={(omittedValues) => ` + ${omittedValues.length} 更多...`} maxTagPlaceholder={(omittedValues) => ` + ${omittedValues.length} 更多...`}
allowClear={true} allowClear={true}
@ -373,7 +421,7 @@ export default observer((props) => {
? cloneDeep(pivotDateColumnsValues)[0] ? cloneDeep(pivotDateColumnsValues)[0]
// .slice(0, rowFields.length) // .slice(0, rowFields.length)
.map((_colArr, _colIndex) => ( .map((_colArr, _colIndex) => (
<Row gutter={8} key={_colArr.join('_')}> <Row gutter={8} key={filterFieldsMapped[pivotDateColumns[0][_colIndex]]?.key || _colIndex}>
<Col flex={'5em'} align={'end'}> <Col flex={'5em'} align={'end'}>
<Text strong>{filterFieldsMapped[pivotDateColumns[0][_colIndex]]?.label}: </Text> <Text strong>{filterFieldsMapped[pivotDateColumns[0][_colIndex]]?.label}: </Text>
</Col> </Col>
@ -416,8 +464,7 @@ export default observer((props) => {
style={{ width: '100%' }} style={{ width: '100%' }}
placeholder={`选择`} placeholder={`选择`}
onChange={(v) => handleColsPick(v)} onChange={(v) => handleColsPick(v)}
// value={sale_store.salesTrade.pickSales} value={columnSelection}
// value={columnSelection}
maxTagCount={2} maxTagCount={2}
maxTagPlaceholder={(omittedValues) => ` + ${omittedValues.length} 更多...`} maxTagPlaceholder={(omittedValues) => ` + ${omittedValues.length} 更多...`}
allowClear={true} allowClear={true}
@ -497,6 +544,9 @@ export default observer((props) => {
<h3> <h3>
透视汇总表: <span style={{ fontSize: 'smaller' }}>{dataFieldAlias[lineConfig.yField].label}</span> 透视汇总表: <span style={{ fontSize: 'smaller' }}>{dataFieldAlias[lineConfig.yField].label}</span>
</h3> </h3>
<Divider orientation="right">
<TableExportBtn label={'pivot'} {...{ columns: targetTableProps.columns, dataSource: pivotTableDataSource }} />
</Divider>
<Table {...targetTableProps} dataSource={pivotTableDataSource} components={{ body: { cell: TdCell } }} /> <Table {...targetTableProps} dataSource={pivotTableDataSource} components={{ body: { cell: TdCell } }} />
</Spin> </Spin>
</section> </section>

Loading…
Cancel
Save