perf: 老客户-分析: 国籍汇总计算

main
Lei OT 3 months ago
parent 16e6ec574a
commit c023dd5b68

@ -1,10 +1,11 @@
import { useContext, useEffect, useState } from 'react'; import { useContext, useEffect, useState } from 'react';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import { toJS } from 'mobx';
import { stores_Context } from '../config'; import { stores_Context } from '../config';
import { Table, Row, Col, Divider, Switch, Space, Tabs, Tooltip } from 'antd'; import { Table, Row, Col, Divider, Switch, Space, Tabs, Tooltip } from 'antd';
import { InfoCircleOutlined } from '@ant-design/icons'; import { InfoCircleOutlined } from '@ant-design/icons';
import SearchForm from '../components/search/SearchForm'; import SearchForm from '../components/search/SearchForm';
import { TableExportBtn, VSTag } from '../components/Data'; import { RenderVSDataCell, TableExportBtn, VSTag } from '../components/Data';
import { fixTo2Decimals, isEmpty } from '@haina/utils-commons'; import { fixTo2Decimals, isEmpty } from '@haina/utils-commons';
// TdCellDataTable // TdCellDataTable
@ -39,8 +40,8 @@ const pivotColOptions = [
const CustomerCareRegularPivot = (props) => { const CustomerCareRegularPivot = (props) => {
const { date_picker_store: searchFormStore, customer_store } = useContext(stores_Context); const { date_picker_store: searchFormStore, customer_store } = useContext(stores_Context);
const { formValues, formValuesToSub, siderBroken } = searchFormStore; const { formValues, formValuesToSub, siderBroken } = searchFormStore;
const { loading, pivotResult, filterColValues, rawData } = customer_store.sales_regular_data; const { loading, pivotResult, filterColValues, rawData, countrySummary } = customer_store.sales_regular_data;
// console.log('', countrySummary);
const [pivotRow, setPivotRow] = useState('operatorName'); const [pivotRow, setPivotRow] = useState('operatorName');
const [pivotCol, setPivotCol] = useState('hasOld'); const [pivotCol, setPivotCol] = useState('hasOld');
const [pivotColLabel, setPivotColLabel] = useState('老客户+推荐'); const [pivotColLabel, setPivotColLabel] = useState('老客户+推荐');
@ -57,36 +58,10 @@ const CustomerCareRegularPivot = (props) => {
useEffect(() => { useEffect(() => {
if ( ! ifmerge) { if ( ! ifmerge) {
// setDataSource(pageData[pivotRow].data);
setDataSource(pivotResult); setDataSource(pivotResult);
// setDataForExport(
// // pageData[pivotRow].data.reduce(
// pivotResult.reduce(
// (r, c) =>
// r.concat(
// [{ ...c, children: undefined }],
// (c?.children || [])
// .reduce((rc, ele) => rc.concat([{ ...ele, [pivotRow]: ele.rowLabel }], [{ ...ele.vsData, [pivotRow]: ele.vsData.rowLabel, vsData: {} }]), [])
// .filter((ele) => ele.SumOrder !== undefined)
// ),
// []
// )
// );
setDataForExportS(pivotResult.reduce((r, c) => r.concat([{...c, children: undefined}], [{ ...c.vsData, vsData: {} }]), []).filter((ele) => ele.SumOrder !== undefined)); setDataForExportS(pivotResult.reduce((r, c) => r.concat([{...c, children: undefined}], [{ ...c.vsData, vsData: {} }]), []).filter((ele) => ele.SumOrder !== undefined));
} else { } else {
// setDataSource(pageData[pivotRow].mergedData); //
// setDataForExport(
// pageData[pivotRow].mergedData.reduce(
// (r, c) =>
// r.concat(
// [{ ...c, children: undefined }],
// c.children.reduce((rc, ele) => rc.concat([{ ...ele, operatorName: ele.rowLabel }], [{ ...ele.vsData, operatorName: ele.vsData.rowLabel, vsData: {} }]), [])
// .filter((ele) => ele.SumOrder !== undefined)
// ),
// []
// )
// );
// setDataForExportS(pageData[pivotRow].mergedData.reduce((r, c) => r.concat([{...c, children: undefined}], [{ ...c.vsData, vsData: {} }]), []).filter((ele) => ele.SumOrder !== undefined));
} }
return () => {}; return () => {};
@ -130,9 +105,10 @@ const CustomerCareRegularPivot = (props) => {
{ key: 'ConfirmPersonNum', title: '✔人数(SUM)', dataIndex: 'ConfirmPersonNum', width: '5em', render: (v, r) => renderVS(v, r, 'ConfirmPersonNum') }, { key: 'ConfirmPersonNum', title: '✔人数(SUM)', dataIndex: 'ConfirmPersonNum', width: '5em', render: (v, r) => renderVS(v, r, 'ConfirmPersonNum') },
{ key: 'confirmTourdays', title: '✔团天数(AVG)', dataIndex: 'confirmTourdays', width: '5em', render: (v, r) => renderVS(v, r, 'confirmTourdays') }, { key: 'confirmTourdays', title: '✔团天数(AVG)', dataIndex: 'confirmTourdays', width: '5em', render: (v, r) => renderVS(v, r, 'confirmTourdays') },
{ key: 'SumML', title: '预计毛利', dataIndex: 'SumML', width: '5em', render: (v, r) => renderVS(v, r, 'SumML') }, // SumML_txt { key: 'SumML', title: '预计毛利', dataIndex: 'SumML', width: '5em', render: (v, r) => renderVS(v, r, 'SumML') }, // SumML_txt
{ key: 'ConfirmRates', title: '成交率', dataIndex: 'ConfirmRates_txt', width: '5em', render: (v, r) => renderVS(v, r, 'ConfirmRates') }, { key: 'ConfirmRates', title: '成交率', dataIndex: 'ConfirmRates_txt', width: '5em', render: (v, r) => renderVS(v, r, 'ConfirmRates'), suffix: '%' },
{ key: 'SingleML', title: '单团毛利', dataIndex: 'SingleML', width: '5em', render: (v, r) => renderVS(v, r, 'SingleML') }, { key: 'SingleML', title: '单团毛利', dataIndex: 'SingleML', width: '5em', render: (v, r) => renderVS(v, r, 'SingleML') },
].map(c => ({...c, sorter: (a, b) => (a[c.key] - b[c.key])})); ].map(c => ({...c, sorter: (a, b) => (a[c.key] - b[c.key])}));
return ( return (
<> <>
<Row gutter={16} className={siderBroken ? '' : 'sticky-top'}> <Row gutter={16} className={siderBroken ? '' : 'sticky-top'}>
@ -167,32 +143,13 @@ const CustomerCareRegularPivot = (props) => {
...ele, ...ele,
children: ( children: (
<> <>
{/* <h2>{ele.label}-老客户, 含推荐</h2> */}
<> <>
<Divider orientation={'right'} style={{backgroundColor: '#fff', margin: 0, padding: '10px 0'}} > <Divider orientation={'right'} style={{backgroundColor: '#fff', margin: 0, padding: '10px 0'}} >
{/* {dataSource.length > 0 && pivotRow === 'operatorName' && (
<Switch
unCheckedChildren="各账户"
checkedChildren="合并"
key={'openOrMerge'}
checked={ifmerge}
onChange={(e) => {
setIfmerge(e);
}}
/>
)}
<Divider type={'vertical'} /> */}
<TableExportBtn <TableExportBtn
btnTxt="导出明细" btnTxt="导出明细"
label={`${formValuesToSub.Date1}-老客户-明细`} label={`${formValuesToSub.Date1}-老客户-明细`}
{...{ columns: [{ title: ele.labelX || ele.label, dataIndex: pivotRow, key: pivotRow }, ...rowColumns], dataSource: rawData }} {...{ columns: [{ title: ele.labelX || ele.label, dataIndex: pivotRow, key: pivotRow }, ...rowColumns], dataSource: rawData }}
/> />
{/* <Divider type={'vertical'} />
<TableExportBtn
btnTxt="导出下表-展开"
label={`${formValuesToSub.Date1}-${ele.label}.老客户`}
{...{ columns: [{ title: ele.label, dataIndex: pivotRow, key: pivotRow }, ...columns], dataSource: dataForExport }}
/> */}
<Divider type={'vertical'} /> <Divider type={'vertical'} />
<TableExportBtn <TableExportBtn
btnTxt="导出下表" btnTxt="导出下表"
@ -209,12 +166,11 @@ const CustomerCareRegularPivot = (props) => {
customer_store.regular_data_pivot(pivotRow, sub); customer_store.regular_data_pivot(pivotRow, sub);
}} }}
items={pivotColOptions.map((col, i) => { items={pivotColOptions.map((col, i) => {
// const SubjectTableComponent = subjectComponents[ele.key];
return { return {
...col, ...col,
children: ( children: (
<Table <Table
sticky sticky={{ offsetHeader: 88 }}
dataSource={dataSource} dataSource={dataSource}
loading={loading} loading={loading}
columns={[ columns={[
@ -229,8 +185,24 @@ const CustomerCareRegularPivot = (props) => {
}, },
...columns, ...columns,
]} ]}
summary={() => {
return (
pivotRow === 'country' &&
countrySummary.map((srow) => (
<Table.Summary.Row key={srow.key}>
<Table.Summary.Cell index1={0}><b>{srow.country}</b></Table.Summary.Cell>
{columns.map((td) => (
<Table.Summary.Cell key={td.key}>
<RenderVSDataCell data1={srow[td.dataIndex]} data2={srow.vsData?.[td.dataIndex]} showDiffData={toJS(formValuesToSub.DateDiff1)} dataSuffix={td.suffix} />
</Table.Summary.Cell>
))}
</Table.Summary.Row>
))
);
}}
pagination={false} pagination={false}
/>) />
),
}; };
})} })}
/> />

@ -68,7 +68,7 @@ export const VSDataTag = ({ diffPercent=0, diffData=0, data1=0, data2=0, dataSuf
* @property {number} data2 * @property {number} data2
* @property {string} dataSuffix * @property {string} dataSuffix
*/ */
export const RenderVSDataCell = ({ showDiffData=false, data1, data2, dataSuffix = '', ...props }) => { export const RenderVSDataCell = ({ showDiffData=false, data1=0, data2=0, dataSuffix = '', ...props }) => {
if (showDiffData) { if (showDiffData) {
return <VSDataTag data1={data1} data2={data2} dataSuffix={dataSuffix} {...props} />; return <VSDataTag data1={data1} data2={data2} dataSuffix={dataSuffix} {...props} />;
} }

@ -2,7 +2,7 @@ import {makeAutoObservable, runInAction, toJS } from "mobx";
import { fetchJSON } from '@haina/utils-request'; import { fetchJSON } from '@haina/utils-request';
import * as config from "../config"; import * as config from "../config";
import { groupsMappedByKey, sitesMappedByCode, pivotBy } from './../libs/ht'; import { groupsMappedByKey, sitesMappedByCode, pivotBy } from './../libs/ht';
import { sortBy, formatPercent, groupBy, isEmpty, uniqWith, formatPercentToFloat } from "@haina/utils-commons"; import { sortBy, formatPercent, groupBy, isEmpty, uniqWith, formatPercentToFloat, fixTo2Decimals } from "@haina/utils-commons";
import { show_vs_tag, } from "./../utils/commons"; import { show_vs_tag, } from "./../utils/commons";
import moment from 'moment'; import moment from 'moment';
@ -14,6 +14,26 @@ const getDetailData = async (param) => {
return json.errcode === 0 ? json.result : []; return json.errcode === 0 ? json.result : [];
}; };
const calcSummaryRow = (data1, data2) => {
const summaryFields = ['ConfirmOrder', 'SumOrder', 'SumML', 'transactions', 'SumPersonNum', 'ConfirmPersonNum', 'ConfirmOrderKPIvalue', 'OrderKPIvalue', 'MLKPIvalue'];
const xSummary = summaryFields.reduce((r, skey) => ({ ...r, [skey]: data1.reduce((a, c) => a + c[skey], 0) }), {});
xSummary.ConfirmRates = xSummary.SumOrder ? fixTo2Decimals((xSummary.ConfirmOrder / xSummary.SumOrder) * 100) : 0;
xSummary.ConfirmRates_txt = xSummary.ConfirmRates; // + '%';
xSummary.confirmTourdays = '-';
xSummary.SingleML = '-';
xSummary._data = data1;
const xSummary2 = summaryFields.reduce((r, skey) => ({ ...r, [skey]: data2.reduce((a, c) => a + c[skey], 0) }), {});
xSummary2.ConfirmRates = xSummary2.SumOrder ? fixTo2Decimals((xSummary2.ConfirmOrder / xSummary2.SumOrder) * 100) : 0;
xSummary2.ConfirmRates_txt = xSummary2.ConfirmRates; // + '%';
xSummary2.confirmTourdays = '-';
xSummary2.SingleML = '-';
xSummary2._data = data2;
xSummary.vsData = xSummary2;
return xSummary;
};
class CustomerStore { class CustomerStore {
constructor(rootStore) { constructor(rootStore) {
@ -476,6 +496,7 @@ class CustomerStore {
// country: { loading: false, data: [], rawData: [], mergedData: [], filterColValues: [] }, // country: { loading: false, data: [], rawData: [], mergedData: [], filterColValues: [] },
// }, // },
pivotResult: [], pivotResult: [],
countrySummary: [],
filterColValues: [], filterColValues: [],
rawDataArr: [], rawDataArr: [],
}; };
@ -556,19 +577,24 @@ class CustomerStore {
const [result1, result2] = this.sales_regular_data.rawDataArr; const [result1, result2] = this.sales_regular_data.rawDataArr;
// const allRows = Array.from(new Set([...result1.filterHasOld.map(row=>row[pivotRow]), ...result2.filterHasOld.map(row=>row[pivotRow])])); // const allRows = Array.from(new Set([...result1.filterHasOld.map(row=>row[pivotRow]), ...result2.filterHasOld.map(row=>row[pivotRow])]));
// console.log(' ------ allRows', allRows); // console.log(' ------ allRows', allRows);
const [{ pivotResult: pivot1, rowValues: rowValues1 }, { pivotResult: pivot2, rowValues: rowValues2 }] = [result1, result2].map(_result => { const [{ pivotResult: pivot1, rowValues: rowValues1 }, { pivotResult: pivot2, rowValues: rowValues2 }] = [result1, result2].map((_result) => {
const dataColField = pivotCol.replace('_txt', ''); const dataColField = pivotCol.replace('_txt', '');
const rawData = pivotCol === 'hasOld' ? _result.filterHasOld : _result.filterHasOld.filter((ele) => ele[dataColField] === '1'); const rawData = pivotCol === 'hasOld' ? _result.filterHasOld : _result.filterHasOld.filter((ele) => ele[dataColField] === '1');
const { data: pivotResult, columnValues: [[rowValues,], columnsKeys, dateKeys] } = pivotBy(rawData, [[pivotRow, pivotCol], [], []]); const {
data: pivotResult,
columnValues: [[rowValues], columnsKeys, dateKeys],
} = pivotBy(rawData, [[pivotRow, pivotCol], [], []]);
return { pivotResult, rowValues }; return { pivotResult, rowValues };
}); });
const allRowValues = Array.from(new Set([...rowValues1, ...rowValues2])); const allRowValues = Array.from(new Set([...rowValues1, ...rowValues2]));
// console.log(' ------ xx', rowValues1); // console.log(' ------ xx', rowValues1);
const rows1 = groupBy(pivot1, pivotRow); const rows1 = groupBy(pivot1, pivotRow);
const rows2 = groupBy(pivot2, pivotRow); const rows2 = groupBy(pivot2, pivotRow);
const pivotResultWithCompare = isEmpty(pivot2) ? pivot1 : allRowValues.reduce((r, rowName) => { const pivotResultWithCompare = isEmpty(pivot2)
const _default = { [pivotRow]: rowName, rowLabel: rows1?.[rowName]?.rowLabel || rows2?.[rowName]?.rowLabel, children: rows1?.[rowName], key: rowName}; ? pivot1
const operatorRow = {...(rows1?.[rowName]?.[0] || _default), vsData: rows2?.[rowName]?.[0] || {}}; : allRowValues.reduce((r, rowName) => {
const _default = { [pivotRow]: rowName, rowLabel: rows1?.[rowName]?.rowLabel || rows2?.[rowName]?.rowLabel, children: rows1?.[rowName], key: rowName };
const operatorRow = { ...(rows1?.[rowName]?.[0] || _default), vsData: rows2?.[rowName]?.[0] || {} };
// 展开的两项: '老客户', '老客户推荐' // 展开的两项: '老客户', '老客户推荐'
// const series1Children = rows1?.[rowName]?.[0]?.children || []; // const series1Children = rows1?.[rowName]?.[0]?.children || [];
// const series2Children = rows2?.[rowName]?.[0]?.children || []; // const series2Children = rows2?.[rowName]?.[0]?.children || [];
@ -588,6 +614,27 @@ class CustomerStore {
(a, b) => JSON.stringify(a) === JSON.stringify(b) (a, b) => JSON.stringify(a) === JSON.stringify(b)
).sort((a, b) => a.text.localeCompare(b.text, 'zh-CN')); ).sort((a, b) => a.text.localeCompare(b.text, 'zh-CN'));
if (pivotRow === 'country') {
const aseanKK = ['新加坡', '马来西亚', '印度尼西亚', '菲律宾', '越南', '泰国', '文莱', '柬埔寨', '东帝汶', '老挝', '缅甸'];
const [asean1, asean2] = [
pivot1.filter((ele) => aseanKK.includes(ele.country)),
pivot2.filter((ele) => aseanKK.includes(ele.country)),
];
const aseanSummary = calcSummaryRow(asean1, asean2);
aseanSummary.key = '东南亚11国';
aseanSummary.country = '东南亚11国';
const eurusdKK = ['美国', '加拿大', '澳大利亚', '英国'];
const [eurusd1, eurusd2] = [
pivot1.filter((ele) => eurusdKK.includes(ele.country)),
pivot2.filter((ele) => eurusdKK.includes(ele.country)),
];
const eurusdSummary = calcSummaryRow(eurusd1, eurusd2);
eurusdSummary.key = '欧美4国';
eurusdSummary.country = '欧美4国';
this.sales_regular_data.countrySummary = [aseanSummary, eurusdSummary];
}
this.sales_regular_data.pivotResult = pivotResultWithCompare; this.sales_regular_data.pivotResult = pivotResultWithCompare;
this.sales_regular_data.filterColValues = filterColValues; this.sales_regular_data.filterColValues = filterColValues;

Loading…
Cancel
Save