主页: 走势: 传统+商务的总额

feature/bak/sales-kpi
Lei OT 2 years ago
parent a427a221a9
commit be2298c5bc

@ -0,0 +1,139 @@
import { observer } from 'mobx-react';
import { Mix } from '@ant-design/plots';
import { merge, isEmpty, groupBy, cloneDeep } from '../utils/commons';
import { dataFieldAlias } from '../libs/ht';
const uniqueByKey = (array, key, pickLast) => {
const seen = new Map();
const isPickLast = pickLast === true;
return array.filter((item) => {
const k = item[key];
const storedItem = seen.get(k);
if (storedItem) {
if (isPickLast) {
seen.set(k, item); // update with last item
}
return false;
}
seen.set(k, item);
return true;
});
};
export default observer((props) => {
const { dataSource, summaryData: areaData, ...config } = props;
const kpiKey = dataFieldAlias[config.yField]?.nestkey?.v;
const seriesData = groupBy(dataSource, (ele) => ele[config.seriesField]);
const pickKey4KPI = Object.keys(seriesData)[0];
const KPIData = (seriesData?.[pickKey4KPI] || []).reduce((r, v) => {
if (!isEmpty(v[kpiKey])) {
// 线 : #F4664A
r.push({ ...v, [config.yField]: v[kpiKey], [config.seriesField]: dataFieldAlias[kpiKey].label, extraLine: true });
}
return r;
}, []);
const dataColors = ['#598cf3', '#69deae', '#FAAD14'];
const colorSets = Object.keys(seriesData)
.sort()
.reduce((obj, k, i) => ({ ...obj, [k]: dataColors[i] }), {});
const { xField, yField, seriesField, tooltip, ...extConfig } = config;
const lineConfig = merge(
{
data: [...dataSource, ...KPIData],
xField,
yField,
seriesField,
point: {
size: 4,
shape: 'cicle',
},
xAxis: false,
yAxis: false,
meta: {
[yField]: {
sync: true,
}
},
// color: ['#598cf3', '#69deae', '#F4664A', '#FAAD14'],
color: (item) => {
const thisSeries = item[config.seriesField];
return thisSeries.includes('目标') ? '#F4664A' : colorSets[thisSeries];
},
lineStyle: (data) => {
// console.log(data);
if (data[config.seriesField].includes('目标')) {
return {
lineDash: [4, 4],
opacity: 0.5,
};
}
return {
opacity: 1,
};
},
},
extConfig
);
const MixConfig = {
appendPadding: 8,
syncViewPadding: true,
tooltip: {
shared: true,
customItems: (originalItems) => {
// process originalItems,
const items = originalItems.map((ele) => ({ ...ele, name: ele.data?.extraLine ? ele.name : `${ele.name} ${dataFieldAlias[yField]?.alias || yField}` }));
return items;
},
},
plots: [
{
type: 'area',
options: {
data: areaData,
xField,
yField,
seriesField,
xAxis: false,
meta: merge(
{
...cloneDeep(dataFieldAlias),
},
{ [xField]: { sync: true }, [yField]: { sync: true } }
),
// color: '#b32b19',
color: '#f58269',
smooth: true,
areaStyle: () => {
return {
fill: 'l(270) 0:#ffffff 0.25:#f8e8e7 0.5:#fac9bd 0.75:#f7a593',
};
},
label: {
offsetY: -8,
},
annotations: areaData.map((d) => {
return {
type: 'dataMarker',
position: d,
point: {
style: {
stroke: '#F4664A',
lineWidth: 1.5,
},
},
};
}),
},
},
{
type: 'line',
options: lineConfig,
},
],
};
return <Mix {...MixConfig} />;
});

@ -57,7 +57,7 @@ export default observer((props) => {
range: [ '#E8EDF3', '#FFF3E1'],
// range: ['#FFbcb8', '#FFe0b0', '#bfeec8'],
measure: ['#5B8FF9', '#61DDAA'],
target: '#39a3f4',
target: kpiVal ? '#FF9845' : '#5B8FF9',
},
label: {
measure: {

@ -1,6 +1,6 @@
import { makeAutoObservable, runInAction, toJS } from 'mobx';
import * as req from '../utils/request';
import { isEmpty, sortBy, pick, merge, fixTo2Decimals, groupBy, sortKeys } from '../utils/commons';
import { isEmpty, sortBy, pick, merge, fixTo2Decimals, groupBy, sortKeys, fixToInt } from '../utils/commons';
import { dataFieldAlias } from './../libs/ht';
class Trade {
@ -88,15 +88,14 @@ class Trade {
Object.assign(queryData, { groupDateType: this.timeLineKey });
const multiData = await this.fetchTradeDataAll(queryData);
const { traditional, biz } = multiData.result1;
// console.log(biz, 'mmmmmmmm', queryData);
const dataT = traditional.map(ele => ({...ele, groupsLabel: '传统'}));
const dataB = biz.map(ele => ({...ele, groupsLabel: '商务'}));
const mergeData = [].concat(dataT, dataB);
// console.log(biz, 'mmmmmmmm', queryData, multiData);
const mergeData = [].concat(traditional, biz);
const dateKeyData = groupBy(mergeData, ele => ele.groupDateVal);
const sortByDateKey = Object.values(sortKeys(dateKeyData)).reduce( (a, b) => a.concat(b), []);
runInAction(() => {
this.timeData.loading = false;
this.timeData.dataSource = sortByDateKey;
this.timeData.origin = multiData.result1;
});
}
@ -214,15 +213,34 @@ class Trade {
const traditional = await this.fetchTradeData(queryData);
const biz = await this.fetchTradeDataBiz(queryData);
const rr = ['result1', 'result2'].reduce((res, resKey) => {
const mergeItem = { traditional: traditional[resKey], biz: biz[resKey] };
const mergeItem = {
traditional: traditional[resKey].map(ele => ({...ele, groupsLabel: `传统 `})), // ${ele.groupsLabel}
biz: biz[resKey].map(ele => ({...ele, groupsLabel: `商务 `})), // ${ele.groupsLabel}
};
const mergeRes = [].concat(traditional[resKey], biz[resKey]);
// const kpiKeys = [];
const groupsData = mergeRes.reduce((r, v) => {
if (v.groupsLabel ) {
(r[v.groupsLabel] || (r[v.groupsLabel] = [])).push(v);
}
return r;
}, {});
const ByDate = sortKeys(groupBy(mergeRes, ele => ele.groupDateVal));
const summaryRows = Object.keys(ByDate).map(dateVal => {
const sumFields = ['ConfirmOrder', 'SumOrder', 'SumML', 'transactions', 'SumPersonNum'].reduce(
(r, skey) => ({ ...r, [skey]: ByDate[dateVal].reduce((a, c) => a + c[skey], 0) }),
ByDate[dateVal]?.[0] || {}
);
const pickFields = pick(ByDate[dateVal], Object.keys(ByDate[dateVal]).filter(_k => _k.endsWith('KPIvalue') ));
return {...sumFields, ...pickFields};
}, {}).map(row => ({...row,
ConfirmRates: row.SumOrder ? fixTo2Decimals((row.ConfirmOrder/row.SumOrder)*100) : 0,
MLKPIrates: row.MLKPIvalue ? fixTo2Decimals((row.SumML/row.MLKPIvalue)*100) : 0,
OrderValue: row.SumOrder ? fixToInt((row.SumML/row.SumOrder)) : 0,
groupsLabel: ``, // ${row.groupsLabel}
ConfirmOrderKPIrates: row.ConfirmOrderKPIvalue ? fixTo2Decimals((row.ConfirmOrder/row.ConfirmOrderKPIvalue)*100) : 0,
OrderKPIrates: row.OrderKPIvalue ? fixTo2Decimals((row.SumOrder/row.OrderKPIvalue)*100) : 0,
// ConfirmRatesKPIrates: 0, // todo:
}));
const summary = Object.keys(groupsData).map(groupsKey => {
return ['ConfirmOrder', 'SumOrder', 'SumML', 'transactions', 'SumPersonNum'].reduce(
(r, skey) => ({ ...r, [skey]: groupsData[groupsKey].reduce((a, c) => a + c[skey], 0) }),
@ -231,9 +249,10 @@ class Trade {
}).map(row => ({...row,
ConfirmRates: row.SumOrder ? fixTo2Decimals((row.ConfirmOrder/row.SumOrder)*100) : 0,
MLKPIrates: row.MLKPIvalue ? fixTo2Decimals((row.SumML/row.MLKPIvalue)*100) : 0,
// todo:
OrderValue: row.SumOrder ? fixToInt((row.SumML/row.SumOrder)) : 0,
groupsLabel: ``, // ${row.groupsLabel}
}));
return Object.assign(res, { [resKey]: Object.assign({}, mergeItem, { summary }) });
return Object.assign(res, { [resKey]: Object.assign({}, mergeItem, { summary, summaryRows }) });
}, {});
return rr;
}
@ -273,7 +292,7 @@ class Trade {
resetData = () => {
this.summaryData = { loading: false, dataSource: [], kpi: {}, };
this.timeData = { loading: false, dataSource: [] };
this.timeData = { loading: false, dataSource: [], origin: {} };
this.BuData = { loading: false, dataSource: [] };
this.sideData = { loading: false, dataSource: {}, monthData: [], yearData: [] };
this.topData = {};
@ -283,7 +302,7 @@ class Trade {
searchPayloadHome = {};
summaryData = { loading: false, dataSource: [], kpi: {}, };
timeData = { loading: false, dataSource: [] };
timeData = { loading: false, dataSource: [], origin: {} };
BuData = { loading: false, dataSource: [] };
sideData = { loading: false, dataSource: {}, monthData: [], yearData: [] };
topData = {};

@ -9,6 +9,7 @@ import StatisticCard2 from '../components/StatisticCard2';
import Bullet from '../components/BulletWithSort';
import Waterfall from '../components/Waterfall';
import LineWithKPI from '../components/LineWithKPI';
import MixTBWithKPI from './../components/MixTBWithKPI';
import Donut from './../components/Donut';
import DataFieldRadio from '../components/DataFieldRadio';
import { datePartOptions } from './../components/DateGroupRadio/date';
@ -152,13 +153,6 @@ export default observer(() => {
setLineConfig({
...cloneDeep(lineConfig),
yField: key,
tooltip: {
customItems: (originalItems) => {
// process originalItems,
const items = originalItems.map((ele) => ({ ...ele, name: ele.data?.extraLine ? ele.name : `${ele.name} ${dataFieldAlias[key]?.alias || key}` }));
return items;
},
},
});
};
const [dateField, setDateField] = useState(timeLineKey);
@ -219,8 +213,8 @@ export default observer(() => {
<Radio.Group options={datePartOptions} optionType="button" onChange={handleChangeDateType} value={dateField} />
</Space>
<Spin spinning={timeData.loading}>
{/* <Line {...lineConfig} data={timeData.dataSource} /> */}
<LineWithKPI dataSource={timeData.dataSource} {...lineConfig} />
{/* <LineWithKPI dataSource={timeData.dataSource} {...lineConfig} /> */}
<MixTBWithKPI dataSource={timeData.dataSource} summaryData={timeData.origin?.summaryRows || []} {...lineConfig} />
</Spin>
</section>
<section>

Loading…
Cancel
Save