perf: 老客户: 订单走势

main
Lei OT 3 months ago
parent 12e99bb816
commit 6ea43a58e2

@ -1,16 +1,17 @@
import React, { useContext, useEffect } from 'react';
import React, { useContext } from 'react';
import { Row, Col, Divider, Table, Tooltip } from 'antd';
import { InfoCircleOutlined } from '@ant-design/icons';
import { utils, writeFileXLSX } from 'xlsx';
import { stores_Context } from '../config';
import { observer } from 'mobx-react';
import SearchForm from './../components/search/SearchForm';
import LineWithAvg from '../components/LineWithAvg';
const Customer_care_regular = () => {
const { orders_store, date_picker_store, customer_store } = useContext(stores_Context);
const regular_data = customer_store.regular_data;
useEffect(() => {}, []);
// useEffect(() => {}, []);
return (
<div>
@ -66,7 +67,7 @@ const Customer_care_regular = () => {
<>
<span>{text}</span>&nbsp;&nbsp;
{<Tooltip key='total_data_tips' title={regular_data.total_data_tips}>
{index === 0 && regular_data.total_data_tips!=='' && <InfoCircleOutlined />}
{index === 0 && regular_data.total_data_tips!=='' && <InfoCircleOutlined className='ant-tag-gold' />}
</Tooltip>}
</>
),
@ -98,6 +99,11 @@ const Customer_care_regular = () => {
rowKey={(record) => record.ItemName}
/>
</Col>
<Col span={24}>
<LineWithAvg dataSource={regular_data.pivotData} loading={regular_data.detail_loading} xField={regular_data.pivotX} yField={regular_data.pivotY} seriesField='_ylabel' showSUM={true} />
</Col>
<Col span={24}>
<Divider orientation="right" plain>
<a
@ -112,7 +118,7 @@ const Customer_care_regular = () => {
<Table
id="table_to_xlsx"
pagination={false}
loading={regular_data.loading}
loading={regular_data.detail_loading}
dataSource={regular_data.data_detail}
scroll={{ x: 1200 }}
columns={[
@ -127,7 +133,7 @@ const Customer_care_regular = () => {
key: 'COLI_ApplyDate',
},
{
title: '订单状态',
title: '订单状态',width: '4rem',
dataIndex: 'OrderState',
key: 'OrderState',
render: (text, record) => <span>{text == 1 ? '成行' : '未成行'}</span>,
@ -188,17 +194,17 @@ const Customer_care_regular = () => {
dataIndex: 'COLI_LineClass',
key: 'COLI_LineClass',
},
{ title: '上次 订单号', dataIndex: 'coli_id_Last', key: 'coli_id_Last', width: '2em',
{ title: '上次 订单号', dataIndex: 'coli_id_Last', key: 'coli_id_Last', width: '4em',
render: (_, r) => ({
props: { style: { backgroundColor: '#5B8FF9'+'1A' } },
children: _,
}), },
{ title: '上次 走团日期', dataIndex: 'COLI_OrderStartDate_Last', key: 'COLI_OrderStartDate_Last',width: '2em',
{ title: '上次 走团日期', dataIndex: 'COLI_OrderStartDate_Last', key: 'COLI_OrderStartDate_Last',width: '4em',
render: (_, r) => ({
props: { style: { backgroundColor: '#5B8FF9'+'1A' } },
children: _,
}), },
{ title: '上次 小组', dataIndex: 'Department_Last', key: 'Department_Last',width: '2em',
{ title: '上次 小组', dataIndex: 'Department_Last', key: 'Department_Last',width: '4em',
render: (_, r) => ({
props: { style: { backgroundColor: '#5B8FF9'+'1A' } },
children: _,

@ -0,0 +1,168 @@
import React, { useEffect, useState } from 'react';
import { Row, Col, Spin } from 'antd';
import { Line } from '@ant-design/plots';
import { observer } from 'mobx-react';
import { dataFieldAlias } from '../libs/ht';
import DateGroupRadio from '../components/DateGroupRadio';
import { cloneDeep, groupBy, sortBy } from '../utils/commons';
export default observer((props) => {
const { dataSource: rawData, showAVG, showSUM, loading, ...config } = props;
const { xField, yField, yFieldAlias, seriesField } = config;
const [dataBeforeXChange, setDataBeforeXChange] = useState([]);
const [dataSource, setDataSource] = useState([]);
const [sumSeries, setSumSeries] = useState([]);
const line_config = {
// data: dataSource,
padding: 'auto',
xField,
yField,
seriesField,
// seriesField: 'rowLabel',
// xAxis: {
// type: 'timeCat',
// },
yAxis: {
min: 0,
maxTickInterval: 5,
},
meta: {
...cloneDeep(dataFieldAlias),
},
// smooth: true,
label: {}, //
legend: {
position: 'right-top',
// title: {
// text: ' ' + dataSource.reduce((a, b) => a + b.SumOrder, 0),
// },
itemMarginBottom: 12, //
},
tooltip: {
customItems: (originalItems) => {
return originalItems
.map((ele) => ({ ...ele, valueR: ele.data[yField] }))
.sort(sortBy('valueR'))
.reverse();
},
},
};
const [lineConfig, setLineConfig] = useState(cloneDeep(line_config));
useEffect(() => {
resetX();
return () => {};
}, [rawData]);
useEffect(() => {
if (lineChartX === 'day') {
setDataBeforeXChange(dataSource);
}
return () => {};
}, [dataSource]);
//
const [lineChartX, setLineChartX] = useState('day');
const orderCountDataMapper = { data1: 'data1', data2: undefined };
const orderCountDataFieldMapper = { 'dateKey': xField, 'valueKey': yField, 'seriesKey': seriesField, _f: 'sum' };
const resetX = () => {
setLineChartX('day');
setDataSource(rawData);
setDataBeforeXChange(rawData);
// ``线, ``线
const byDays = groupBy(rawData, xField);
const sumY = rawData.reduce((a, b) => a + b[yField], 0);
const avgVal = Math.round(sumY / (Object.keys(byDays).length));
const avgLine = [
{ type: 'text', position: ['start', avgVal], content: avgVal, offsetX: -15, style: { fill: '#F4664A', textBaseline: 'bottom' } },
{ type: 'line', start: [-10, avgVal], end: ['max', avgVal], style: { stroke: '#F4664A', lineDash: [2, 2] } },
];
setLineConfig({ ...lineConfig, yField, xField, annotations: avgLine });
if (showSUM) {
const _sumLine = Object.keys(byDays).reduce((r, _d) => {
const summaryVal = byDays[_d].reduce((rows, row) => rows + row[yField], 0);
r.push({ ...byDays[_d][0], [yField]: summaryVal, [seriesField]: '总计' });
return r;
}, []);
// console.log(_sumLine.map((ele) => ele[yField]));
setSumSeries(_sumLine);
}
};
const onChangeXDateFieldGroup = (value, data, avg1) => {
// console.log(value, data, avg1);
const _sumLine = [];
const { xField, yField, seriesField } = lineConfig;
const groupByDate = data.reduce((r, v) => {
(r[v[xField]] || (r[v[xField]] = [])).push(v);
return r;
}, {});
// console.log(groupByDate);
const _data = Object.keys(groupByDate).reduce((r, _d) => {
const summaryVal = groupByDate[_d].reduce((rows, row) => rows + row[yField], 0);
_sumLine.push({ ...groupByDate[_d][0], [yField]: summaryVal, [seriesField]: '总计' });
const xAxisGroup = groupByDate[_d].reduce((a, v) => {
(a[v[seriesField]] || (a[v[seriesField]] = [])).push(v);
return a;
}, {});
// console.log(xAxisGroup);
Object.keys(xAxisGroup).map((_group) => {
const summaryVal = xAxisGroup[_group].reduce((rows, row) => rows + row[yField], 0);
r.push({ ...xAxisGroup[_group][0], [yField]: summaryVal, });
return _group;
});
return r;
}, []);
// const _sum = Object.values(groupBy(_data, 'dateGroup')).reduce((ac, b) => ({...b, [yField]: 0}), {});
// console.log(xField, avg1);
// console.log('date source=====', _data);
setLineChartX(value);
setDataSource(_data);
if (showSUM) {
setSumSeries(_sumLine);
}
// setAvgLine1(avg1);
const avg1Int = Math.round(avg1);
const mergedConfig = { ...lineConfig,
annotations: [
{ type: 'text', position: ['start', avg1Int], content: avg1Int, offsetX: -15, style: { fill: '#F4664A', textBaseline: 'bottom' } },
{ type: 'line', start: [-10, avg1Int], end: ['max', avg1Int], style: { stroke: '#F4664A', lineDash: [2, 2] } },
],
};
// console.log(mergedConfig);
setLineConfig(mergedConfig);
};
return (
<section>
<Row gutter={16} justify={'space-between'} className="mb-1">
<Col flex={'auto'}>
<h3>
走势: <span style={{ fontSize: 'smaller' }}>{dataFieldAlias[lineConfig.yField].label}</span>
</h3>
</Col>
<Col style={{ textAlign: 'right' }} align={'end'}>
<DateGroupRadio
visible={true}
dataRaw={{ data1: dataBeforeXChange }}
onChange={onChangeXDateFieldGroup}
value={lineChartX}
dataMapper={orderCountDataMapper}
fieldMapper={orderCountDataFieldMapper}
/>
</Col>
</Row>
<Spin spinning={loading}>
<Line {...lineConfig} data={[].concat(dataSource, sumSeries)} />
</Spin>
</section>
);
});

@ -2,6 +2,8 @@ import {makeAutoObservable, runInAction} from "mobx";
import { fetchJSON } from '../utils/request';
import * as config from "../config";
import { groupsMappedByKey, sitesMappedByCode, pivotBy } from './../libs/ht';
import { sortBy } from "../utils/commons";
import moment from 'moment';
/**
* 用于透视的数据
@ -100,7 +102,10 @@ class CustomerStore {
// 老客户 beign
regular_customer_order(get_detail = false) {
let pivotByOrder = 'SumOrder';
let pivotByDate = 'applyDate';
this.regular_data.loading = true;
this.regular_data.detail_loading = get_detail;
const date_picker_store = this.rootStore.date_picker_store;
let url = '/service-tourdesign/RegularCusOrder';
url += '?Website=' + this.regular_data.webcode.toString() + '&DEI_SNList=' + this.regular_data.groups.toString();
@ -108,8 +113,12 @@ class CustomerStore {
url += '&ApplydateCheck=1&EntrancedateCheck=0&ConfirmDateCheck=0';
} else if(String(this.regular_data.date_type).toLowerCase() === 'confirmdate'){
url += '&ApplydateCheck=0&EntrancedateCheck=0&ConfirmDateCheck=1';
pivotByOrder = 'ConfirmOrder';
pivotByDate = 'confirmDate';
}else {
url += '&ApplydateCheck=0&EntrancedateCheck=1&ConfirmDateCheck=0';
pivotByOrder = 'ConfirmOrder';
pivotByDate = 'startDate';
}
url += '&ApplydateStart=' + date_picker_store.start_date.format(config.DATE_FORMAT) + '&ApplydateEnd=' + date_picker_store.end_date.format(config.SMALL_DATETIME_FORMAT);
url += '&EntrancedateStart=' + date_picker_store.start_date.format(config.DATE_FORMAT) + '&EntrancedateEnd=' + date_picker_store.end_date.format(config.SMALL_DATETIME_FORMAT);
@ -126,9 +135,30 @@ class CustomerStore {
.then((json) => {
runInAction(() => {
if (get_detail) {
this.regular_data.detail_loading = false;
this.regular_data.data_detail = json;
const dump_l = (json || []).filter(ele => ele.COLI_IsOld !== '' && ele.COLI_IsCusCommend !== '').length;
this.regular_data.total_data_tips = dump_l > 0 ? `包含 ${dump_l} 条同时勾选的数据` : '';
/** 使用明细数据画图 */
const data_detail = (json || []).map((ele) => ({
...ele,
key: ele.COLI_ID,
orderState: ele.OrderState,
applyDate: moment(ele.COLI_ApplyDate).format('YYYY-MM-DD'),
startDate: ele.COLI_OrderStartDate,
confirmDate: moment(ele.COLI_ConfirmDate).format('YYYY-MM-DD'),
}));
const { data: IsOldData, } = pivotBy(data_detail.filter(ele => ele.COLI_IsOld === '是'), [['COLI_IsOld', ], [], pivotByDate]);
const { data: isCusCommendData, } = pivotBy(data_detail.filter(ele => ele.COLI_IsCusCommend === '是'), [['COLI_IsCusCommend', ], [], pivotByDate]);
// console.log('IsOldData====', IsOldData, '\nisCusCommend', isCusCommendData);
// 合并成两个系列
const seriesData = [].concat(IsOldData.map(ele => ({...ele, _ylabel: '老客户'})), isCusCommendData.map(ele => ({...ele, _ylabel: '老客户推荐'})),).sort(sortBy(pivotByDate));
// console.log('seriesData====', seriesData);
this.regular_data.pivotData = seriesData; // { IsOldData, isCusCommendData, };
this.regular_data.pivotY = pivotByOrder;
this.regular_data.pivotX = pivotByDate;
} else {
this.regular_data.data = json;
}
@ -159,6 +189,7 @@ class CustomerStore {
regular_data = {
loading: false,
detail_loading: false,
data: [],
data_detail: [],
total_data_tips: '',
@ -179,6 +210,10 @@ class CustomerStore {
WebCode: undefined, // ['ALL'].map(kk => sitesMappedByCode[kk]),
DateType: { key: 'applyDate', label: '提交日期'},
},
pivotData: [],
pivotY: 'SumOrder',
pivotX: 'applyDate',
};
// 老客户 end

Loading…
Cancel
Save