You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dashboard/src/components/BulletWithSort.jsx

138 lines
5.0 KiB
JavaScript

import { useEffect, useState } from 'react';
import { observer } from 'mobx-react';
import { Bullet } from '@ant-design/plots';
import { sortBy, merge, isEmpty } from '../utils/commons';
import { dataFieldAlias } from '../libs/ht';
export default observer((props) => {
const { dataSource, itemLength, ...extProps } = props;
// 处理进度图的数据格式, number -> array
const dataParser = (origin) => {
const { measureField, rangeField, targetField } = extProps;
const measureFieldArrKey = `${measureField}_arr`;
const maxKPI = Math.max(...(origin || []).map((ele) => (ele?.[targetField] || 0)));
const maxValue = Math.max(...(origin || []).map((ele) => ele[measureField]));
const _max = Math.max(maxKPI, maxValue);
const sortData = origin.sort(sortBy(measureField)).slice(-itemLength);
// 顶格的值定在更远
const _parseData = sortData?.map((ele) => ({ ...ele,
[rangeField]: [0, Math.ceil(_max / 0.9)],
// [measureField]: [ele[measureField]],
[measureField]: ele[measureFieldArrKey] || [ele[measureField]],
[targetField]: (ele?.[targetField] || 0)
}));
return _parseData;
};
const dataMapped = dataSource.reduce((r, v) => ({...r, [v.groupsLabel]: v}), {});
const ifMergeTB = isEmpty(dataSource) ? false : !isEmpty(dataSource[0]?.[`${extProps.measureField}_arr`]);
const [parseData, setParseData] = useState([]);
useEffect(() => {
setParseData(dataParser(dataSource));
return () => {};
}, [extProps.measureField, dataSource]);
const config = merge({
color: {
range: [ '#FFF3E1', '#FFF3E1'],
// range: [ '#FFF3E1', '#FFF3E1', '#FFe0b0', '#bfeec8'], // '#FFbcb8', '#FFe0b0',
measure: ['#5B8FF9', '#61ddaa'],
target: '#FF9845',
},
label: {
target: false,
measure: {
position: extProps?.layout === 'vertical' ? 'top' : 'right',
// formatter: (v, ...d) => {
// return dataFieldAlias[extProps.measureField]?.formatter(v[extProps.measureField]) || v;
// },
content: (item, ...r) => {
const val = isEmpty(dataMapped) ? 0 : dataMapped[item.groupsLabel][extProps.measureField];
return String(item?.mKey || '_0').endsWith('_0') ? '' : dataFieldAlias[extProps.measureField]?.formatter(val) || val;
}
},
},
xAxis: {
line: null,
label: {
autoHide: false,
autoRotate: true,
},
},
yAxis: false,
// 自定义 legend
legend: {
custom: true,
position: 'bottom',
items: [
{
value: ifMergeTB ? '传统' : '实际',
name: ifMergeTB ? '传统' : '实际',
marker: {
symbol: 'square',
style: {
fill: '#5B8FF9',
r: 5,
},
},
},
...(ifMergeTB ? [{
value: '商务',
name: '商务',
marker: {
symbol: 'square',
style: {
fill: '#61ddaa',
r: 5,
},
},
}] : []),
{
value: '目标',
name: '目标',
marker: {
symbol: 'line',
style: {
stroke: '#FF9845', // '#39a3f4',
r: 5,
},
},
},
],
},
// ? 全局的alias不起作用
tooltip: {
customItems: (originalItems) => {
// process originalItems,
const measureIndex = originalItems[0].name.split('_');
const measureKey = measureIndex[0];
const measureName = measureKey.endsWith('KPIvalue') ? '' : measureIndex[1] === 0 ? '传统' : '商务';
const measureFieldArrKey = `${measureKey}_arr`;
const kpiKey = dataFieldAlias[measureKey]?.nestkey?.v;
const mItems = (measureName && !String(measureKey).toLowerCase().endsWith('rates'))
? originalItems.reduce((r, ele) => {
const _itemMeasures = dataMapped[ele.title][measureFieldArrKey];
r.push({ ...ele, color: '#5B8FF9', value: dataFieldAlias[measureKey]?.formatter(Number(_itemMeasures[0])), name: '传统' });
r.push({ ...ele, color: '#61ddaa', value: dataFieldAlias[measureKey]?.formatter(Number(_itemMeasures[1])), name: '商务' });
const _itemMeasureKPIv = dataMapped[ele.title][kpiKey];
if (kpiKey && _itemMeasureKPIv) {
r.push({ ...ele, color: '#FF9845', value: dataFieldAlias[measureKey]?.formatter(Number(_itemMeasureKPIv)), name: dataFieldAlias[kpiKey].label });
}
return r;
}, [])
: originalItems.map((ele) => ({
...ele,
value: dataFieldAlias[measureKey]?.formatter(Number(ele.value)),
name: dataFieldAlias[measureKey]?.alias || measureKey,
}));
return mItems;
},
},
}, extProps);
return (
<>
<Bullet {...config} data={parseData} />
</>
);
});