|
|
@ -18,18 +18,20 @@ const filterFields = [
|
|
|
|
{ key: 'country', label: '国籍' },
|
|
|
|
{ key: 'country', label: '国籍' },
|
|
|
|
{ key: 'CLI_NO', label: '线路' },
|
|
|
|
{ key: 'CLI_NO', label: '线路' },
|
|
|
|
// { key: 'destination', label: '目的地' },
|
|
|
|
// { key: 'destination', label: '目的地' },
|
|
|
|
{ key: 'COLI_LineClass', label: '页面类型' },
|
|
|
|
{ key: 'COLI_LineClass', label: '页面渠道' },
|
|
|
|
{ key: 'guestGroupType', label: '客群类别' },
|
|
|
|
{ key: 'guestGroupType', label: '客群类别' },
|
|
|
|
{ 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'], []] },
|
|
|
|
// { label: '[ 国籍×客群 ]×[ ]', fields: [['country', 'guestGroupType'], []] },
|
|
|
|
// { label: '[ 国籍×客群 ]×[ ]', fields: [['country', 'guestGroupType'], []] },
|
|
|
|
];
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
@ -40,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([]);
|
|
|
@ -75,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({
|
|
|
@ -88,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);
|
|
|
|
// 行列的选项值
|
|
|
|
// 行列的选项值
|
|
|
@ -118,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',
|
|
|
@ -128,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: {
|
|
|
@ -138,32 +174,31 @@ export default observer((props) => {
|
|
|
|
itemMarginBottom: 12, // 垂直间距
|
|
|
|
itemMarginBottom: 12, // 垂直间距
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const [lineConfig, setLineConfig] = useState(cloneDeep(line_config));
|
|
|
|
const [lineConfig, setLineConfig] = useState(cloneDeep(line_config));
|
|
|
|
|
|
|
|
|
|
|
|
// 透视配置:行列选项
|
|
|
|
// 透视配置:行列选项
|
|
|
|
// const [leftFields, setLeftFields] = useState(filterFields);
|
|
|
|
// const [leftFields, setLeftFields] = useState(filterFields);
|
|
|
|
const [rightFields, setRightFields] = useState(filterFields); // select 的option
|
|
|
|
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)));
|
|
|
|
!isEmpty(col) ? setColumnSelection(filterFieldsMapped[col[0]]) : setColumnSelection([]);
|
|
|
|
!isEmpty(col) ? setColumnSelection(filterFieldsMapped[col[0]]) : setColumnSelection([]);
|
|
|
|
setRowFields(row);
|
|
|
|
setRowFields(row);
|
|
|
|
|
|
|
|
setColumnFields(col);
|
|
|
|
resetItemFilter();
|
|
|
|
resetItemFilter();
|
|
|
|
|
|
|
|
|
|
|
|
setPivotDateColumns(pivotFields);
|
|
|
|
setPivotDateColumns(pivotFields);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const resetFields = () => {
|
|
|
|
const resetFields = () => {
|
|
|
|
// setRowFields([]);
|
|
|
|
setRowFields([]);
|
|
|
|
// setColumnFields([]);
|
|
|
|
setColumnFields([]);
|
|
|
|
setRowSelection([]);
|
|
|
|
setRowSelection([]);
|
|
|
|
setColumnSelection([]);
|
|
|
|
setColumnSelection([]);
|
|
|
|
resetItemFilter();
|
|
|
|
resetItemFilter();
|
|
|
@ -242,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();
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
@ -250,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);
|
|
|
@ -288,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',
|
|
|
|
})),
|
|
|
|
})),
|
|
|
|
})),
|
|
|
|
})),
|
|
|
@ -312,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: {
|
|
|
@ -385,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>
|
|
|
|